diff options
450 files changed, 17654 insertions, 7433 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index ab8300f67182..325cfd1d6d99 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ | 9 | DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ |
10 | kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ | 10 | kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ |
11 | procfs-guide.xml writing_usb_driver.xml networking.xml \ | 11 | writing_usb_driver.xml networking.xml \ |
12 | kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ | 12 | kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ |
13 | gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ | 13 | gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ |
14 | genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ | 14 | genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ |
@@ -32,10 +32,10 @@ PS_METHOD = $(prefer-db2x) | |||
32 | 32 | ||
33 | ### | 33 | ### |
34 | # The targets that may be used. | 34 | # The targets that may be used. |
35 | PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs media | 35 | PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks |
36 | 36 | ||
37 | BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) | 37 | BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) |
38 | xmldocs: $(BOOKS) | 38 | xmldocs: $(BOOKS) xmldoclinks |
39 | sgmldocs: xmldocs | 39 | sgmldocs: xmldocs |
40 | 40 | ||
41 | PS := $(patsubst %.xml, %.ps, $(BOOKS)) | 41 | PS := $(patsubst %.xml, %.ps, $(BOOKS)) |
@@ -45,15 +45,24 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) | |||
45 | pdfdocs: $(PDF) | 45 | pdfdocs: $(PDF) |
46 | 46 | ||
47 | HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) | 47 | HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) |
48 | htmldocs: media $(HTML) | 48 | htmldocs: $(HTML) |
49 | $(call build_main_index) | 49 | $(call build_main_index) |
50 | $(call build_images) | ||
50 | 51 | ||
51 | MAN := $(patsubst %.xml, %.9, $(BOOKS)) | 52 | MAN := $(patsubst %.xml, %.9, $(BOOKS)) |
52 | mandocs: $(MAN) | 53 | mandocs: $(MAN) |
53 | 54 | ||
54 | media: | 55 | build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ |
55 | mkdir -p $(srctree)/Documentation/DocBook/media/ | 56 | cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/ |
56 | cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(srctree)/Documentation/DocBook/media/ | 57 | |
58 | xmldoclinks: | ||
59 | ifneq ($(objtree),$(srctree)) | ||
60 | for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \ | ||
61 | rm -f $(objtree)/Documentation/DocBook/$$dep \ | ||
62 | && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \ | ||
63 | || exit; \ | ||
64 | done | ||
65 | endif | ||
57 | 66 | ||
58 | installmandocs: mandocs | 67 | installmandocs: mandocs |
59 | mkdir -p /usr/local/man/man9/ | 68 | mkdir -p /usr/local/man/man9/ |
@@ -65,7 +74,7 @@ KERNELDOC = $(srctree)/scripts/kernel-doc | |||
65 | DOCPROC = $(objtree)/scripts/basic/docproc | 74 | DOCPROC = $(objtree)/scripts/basic/docproc |
66 | 75 | ||
67 | XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl | 76 | XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl |
68 | #XMLTOFLAGS += --skip-validation | 77 | XMLTOFLAGS += --skip-validation |
69 | 78 | ||
70 | ### | 79 | ### |
71 | # DOCPROC is used for two purposes: | 80 | # DOCPROC is used for two purposes: |
@@ -101,17 +110,6 @@ endif | |||
101 | # Changes in kernel-doc force a rebuild of all documentation | 110 | # Changes in kernel-doc force a rebuild of all documentation |
102 | $(BOOKS): $(KERNELDOC) | 111 | $(BOOKS): $(KERNELDOC) |
103 | 112 | ||
104 | ### | ||
105 | # procfs guide uses a .c file as example code. | ||
106 | # This requires an explicit dependency | ||
107 | C-procfs-example = procfs_example.xml | ||
108 | C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example)) | ||
109 | $(obj)/procfs-guide.xml: $(C-procfs-example2) | ||
110 | |||
111 | # List of programs to build | ||
112 | ##oops, this is a kernel module::hostprogs-y := procfs_example | ||
113 | obj-m += procfs_example.o | ||
114 | |||
115 | # Tell kbuild to always build the programs | 113 | # Tell kbuild to always build the programs |
116 | always := $(hostprogs-y) | 114 | always := $(hostprogs-y) |
117 | 115 | ||
@@ -238,7 +236,7 @@ clean-files := $(DOCBOOKS) \ | |||
238 | $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ | 236 | $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ |
239 | $(patsubst %.xml, %.html, $(DOCBOOKS)) \ | 237 | $(patsubst %.xml, %.html, $(DOCBOOKS)) \ |
240 | $(patsubst %.xml, %.9, $(DOCBOOKS)) \ | 238 | $(patsubst %.xml, %.9, $(DOCBOOKS)) \ |
241 | $(C-procfs-example) $(index) | 239 | $(index) |
242 | 240 | ||
243 | clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man | 241 | clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man |
244 | 242 | ||
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl index bb5ab741220e..c725cb852c54 100644 --- a/Documentation/DocBook/media-entities.tmpl +++ b/Documentation/DocBook/media-entities.tmpl | |||
@@ -23,6 +23,7 @@ | |||
23 | <!ENTITY VIDIOC-ENUMINPUT "<link linkend='vidioc-enuminput'><constant>VIDIOC_ENUMINPUT</constant></link>"> | 23 | <!ENTITY VIDIOC-ENUMINPUT "<link linkend='vidioc-enuminput'><constant>VIDIOC_ENUMINPUT</constant></link>"> |
24 | <!ENTITY VIDIOC-ENUMOUTPUT "<link linkend='vidioc-enumoutput'><constant>VIDIOC_ENUMOUTPUT</constant></link>"> | 24 | <!ENTITY VIDIOC-ENUMOUTPUT "<link linkend='vidioc-enumoutput'><constant>VIDIOC_ENUMOUTPUT</constant></link>"> |
25 | <!ENTITY VIDIOC-ENUMSTD "<link linkend='vidioc-enumstd'><constant>VIDIOC_ENUMSTD</constant></link>"> | 25 | <!ENTITY VIDIOC-ENUMSTD "<link linkend='vidioc-enumstd'><constant>VIDIOC_ENUMSTD</constant></link>"> |
26 | <!ENTITY VIDIOC-ENUM-DV-PRESETS "<link linkend='vidioc-enum-dv-presets'><constant>VIDIOC_ENUM_DV_PRESETS</constant></link>"> | ||
26 | <!ENTITY VIDIOC-ENUM-FMT "<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>"> | 27 | <!ENTITY VIDIOC-ENUM-FMT "<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>"> |
27 | <!ENTITY VIDIOC-ENUM-FRAMEINTERVALS "<link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>"> | 28 | <!ENTITY VIDIOC-ENUM-FRAMEINTERVALS "<link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>"> |
28 | <!ENTITY VIDIOC-ENUM-FRAMESIZES "<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>"> | 29 | <!ENTITY VIDIOC-ENUM-FRAMESIZES "<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>"> |
@@ -30,6 +31,8 @@ | |||
30 | <!ENTITY VIDIOC-G-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_G_AUDOUT</constant></link>"> | 31 | <!ENTITY VIDIOC-G-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_G_AUDOUT</constant></link>"> |
31 | <!ENTITY VIDIOC-G-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_G_CROP</constant></link>"> | 32 | <!ENTITY VIDIOC-G-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_G_CROP</constant></link>"> |
32 | <!ENTITY VIDIOC-G-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_G_CTRL</constant></link>"> | 33 | <!ENTITY VIDIOC-G-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_G_CTRL</constant></link>"> |
34 | <!ENTITY VIDIOC-G-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_G_DV_PRESET</constant></link>"> | ||
35 | <!ENTITY VIDIOC-G-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_G_DV_TIMINGS</constant></link>"> | ||
33 | <!ENTITY VIDIOC-G-ENC-INDEX "<link linkend='vidioc-g-enc-index'><constant>VIDIOC_G_ENC_INDEX</constant></link>"> | 36 | <!ENTITY VIDIOC-G-ENC-INDEX "<link linkend='vidioc-g-enc-index'><constant>VIDIOC_G_ENC_INDEX</constant></link>"> |
34 | <!ENTITY VIDIOC-G-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_G_EXT_CTRLS</constant></link>"> | 37 | <!ENTITY VIDIOC-G-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_G_EXT_CTRLS</constant></link>"> |
35 | <!ENTITY VIDIOC-G-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_G_FBUF</constant></link>"> | 38 | <!ENTITY VIDIOC-G-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_G_FBUF</constant></link>"> |
@@ -53,6 +56,7 @@ | |||
53 | <!ENTITY VIDIOC-QUERYCTRL "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYCTRL</constant></link>"> | 56 | <!ENTITY VIDIOC-QUERYCTRL "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYCTRL</constant></link>"> |
54 | <!ENTITY VIDIOC-QUERYMENU "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYMENU</constant></link>"> | 57 | <!ENTITY VIDIOC-QUERYMENU "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYMENU</constant></link>"> |
55 | <!ENTITY VIDIOC-QUERYSTD "<link linkend='vidioc-querystd'><constant>VIDIOC_QUERYSTD</constant></link>"> | 58 | <!ENTITY VIDIOC-QUERYSTD "<link linkend='vidioc-querystd'><constant>VIDIOC_QUERYSTD</constant></link>"> |
59 | <!ENTITY VIDIOC-QUERY-DV-PRESET "<link linkend='vidioc-query-dv-preset'><constant>VIDIOC_QUERY_DV_PRESET</constant></link>"> | ||
56 | <!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>"> | 60 | <!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>"> |
57 | <!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>"> | 61 | <!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>"> |
58 | <!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>"> | 62 | <!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>"> |
@@ -60,6 +64,8 @@ | |||
60 | <!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>"> | 64 | <!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>"> |
61 | <!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>"> | 65 | <!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>"> |
62 | <!ENTITY VIDIOC-S-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_S_CTRL</constant></link>"> | 66 | <!ENTITY VIDIOC-S-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_S_CTRL</constant></link>"> |
67 | <!ENTITY VIDIOC-S-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_S_DV_PRESET</constant></link>"> | ||
68 | <!ENTITY VIDIOC-S-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_S_DV_TIMINGS</constant></link>"> | ||
63 | <!ENTITY VIDIOC-S-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_S_EXT_CTRLS</constant></link>"> | 69 | <!ENTITY VIDIOC-S-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_S_EXT_CTRLS</constant></link>"> |
64 | <!ENTITY VIDIOC-S-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_S_FBUF</constant></link>"> | 70 | <!ENTITY VIDIOC-S-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_S_FBUF</constant></link>"> |
65 | <!ENTITY VIDIOC-S-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>"> | 71 | <!ENTITY VIDIOC-S-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>"> |
@@ -118,6 +124,7 @@ | |||
118 | <!-- Structures --> | 124 | <!-- Structures --> |
119 | <!ENTITY v4l2-audio "struct <link linkend='v4l2-audio'>v4l2_audio</link>"> | 125 | <!ENTITY v4l2-audio "struct <link linkend='v4l2-audio'>v4l2_audio</link>"> |
120 | <!ENTITY v4l2-audioout "struct <link linkend='v4l2-audioout'>v4l2_audioout</link>"> | 126 | <!ENTITY v4l2-audioout "struct <link linkend='v4l2-audioout'>v4l2_audioout</link>"> |
127 | <!ENTITY v4l2-bt-timings "struct <link linkend='v4l2-bt-timings'>v4l2_bt_timings</link>"> | ||
121 | <!ENTITY v4l2-buffer "struct <link linkend='v4l2-buffer'>v4l2_buffer</link>"> | 128 | <!ENTITY v4l2-buffer "struct <link linkend='v4l2-buffer'>v4l2_buffer</link>"> |
122 | <!ENTITY v4l2-capability "struct <link linkend='v4l2-capability'>v4l2_capability</link>"> | 129 | <!ENTITY v4l2-capability "struct <link linkend='v4l2-capability'>v4l2_capability</link>"> |
123 | <!ENTITY v4l2-captureparm "struct <link linkend='v4l2-captureparm'>v4l2_captureparm</link>"> | 130 | <!ENTITY v4l2-captureparm "struct <link linkend='v4l2-captureparm'>v4l2_captureparm</link>"> |
@@ -128,6 +135,9 @@ | |||
128 | <!ENTITY v4l2-dbg-chip-ident "struct <link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link>"> | 135 | <!ENTITY v4l2-dbg-chip-ident "struct <link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link>"> |
129 | <!ENTITY v4l2-dbg-match "struct <link linkend='v4l2-dbg-match'>v4l2_dbg_match</link>"> | 136 | <!ENTITY v4l2-dbg-match "struct <link linkend='v4l2-dbg-match'>v4l2_dbg_match</link>"> |
130 | <!ENTITY v4l2-dbg-register "struct <link linkend='v4l2-dbg-register'>v4l2_dbg_register</link>"> | 137 | <!ENTITY v4l2-dbg-register "struct <link linkend='v4l2-dbg-register'>v4l2_dbg_register</link>"> |
138 | <!ENTITY v4l2-dv-enum-preset "struct <link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link>"> | ||
139 | <!ENTITY v4l2-dv-preset "struct <link linkend='v4l2-dv-preset'>v4l2_dv_preset</link>"> | ||
140 | <!ENTITY v4l2-dv-timings "struct <link linkend='v4l2-dv-timings'>v4l2_dv_timings</link>"> | ||
131 | <!ENTITY v4l2-enc-idx "struct <link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>"> | 141 | <!ENTITY v4l2-enc-idx "struct <link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>"> |
132 | <!ENTITY v4l2-enc-idx-entry "struct <link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>"> | 142 | <!ENTITY v4l2-enc-idx-entry "struct <link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>"> |
133 | <!ENTITY v4l2-encoder-cmd "struct <link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>"> | 143 | <!ENTITY v4l2-encoder-cmd "struct <link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>"> |
@@ -243,6 +253,10 @@ | |||
243 | <!ENTITY sub-enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml"> | 253 | <!ENTITY sub-enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml"> |
244 | <!ENTITY sub-enuminput SYSTEM "v4l/vidioc-enuminput.xml"> | 254 | <!ENTITY sub-enuminput SYSTEM "v4l/vidioc-enuminput.xml"> |
245 | <!ENTITY sub-enumoutput SYSTEM "v4l/vidioc-enumoutput.xml"> | 255 | <!ENTITY sub-enumoutput SYSTEM "v4l/vidioc-enumoutput.xml"> |
256 | <!ENTITY sub-enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml"> | ||
257 | <!ENTITY sub-g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml"> | ||
258 | <!ENTITY sub-query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml"> | ||
259 | <!ENTITY sub-g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml"> | ||
246 | <!ENTITY sub-enumstd SYSTEM "v4l/vidioc-enumstd.xml"> | 260 | <!ENTITY sub-enumstd SYSTEM "v4l/vidioc-enumstd.xml"> |
247 | <!ENTITY sub-g-audio SYSTEM "v4l/vidioc-g-audio.xml"> | 261 | <!ENTITY sub-g-audio SYSTEM "v4l/vidioc-g-audio.xml"> |
248 | <!ENTITY sub-g-audioout SYSTEM "v4l/vidioc-g-audioout.xml"> | 262 | <!ENTITY sub-g-audioout SYSTEM "v4l/vidioc-g-audioout.xml"> |
@@ -333,6 +347,10 @@ | |||
333 | <!ENTITY enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml"> | 347 | <!ENTITY enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml"> |
334 | <!ENTITY enuminput SYSTEM "v4l/vidioc-enuminput.xml"> | 348 | <!ENTITY enuminput SYSTEM "v4l/vidioc-enuminput.xml"> |
335 | <!ENTITY enumoutput SYSTEM "v4l/vidioc-enumoutput.xml"> | 349 | <!ENTITY enumoutput SYSTEM "v4l/vidioc-enumoutput.xml"> |
350 | <!ENTITY enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml"> | ||
351 | <!ENTITY g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml"> | ||
352 | <!ENTITY query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml"> | ||
353 | <!ENTITY g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml"> | ||
336 | <!ENTITY enumstd SYSTEM "v4l/vidioc-enumstd.xml"> | 354 | <!ENTITY enumstd SYSTEM "v4l/vidioc-enumstd.xml"> |
337 | <!ENTITY g-audio SYSTEM "v4l/vidioc-g-audio.xml"> | 355 | <!ENTITY g-audio SYSTEM "v4l/vidioc-g-audio.xml"> |
338 | <!ENTITY g-audioout SYSTEM "v4l/vidioc-g-audioout.xml"> | 356 | <!ENTITY g-audioout SYSTEM "v4l/vidioc-g-audioout.xml"> |
diff --git a/Documentation/DocBook/media-indices.tmpl b/Documentation/DocBook/media-indices.tmpl index 9e30a236d74f..78d6031de001 100644 --- a/Documentation/DocBook/media-indices.tmpl +++ b/Documentation/DocBook/media-indices.tmpl | |||
@@ -36,6 +36,7 @@ | |||
36 | <indexentry><primaryie>enum <link linkend='v4l2-preemphasis'>v4l2_preemphasis</link></primaryie></indexentry> | 36 | <indexentry><primaryie>enum <link linkend='v4l2-preemphasis'>v4l2_preemphasis</link></primaryie></indexentry> |
37 | <indexentry><primaryie>struct <link linkend='v4l2-audio'>v4l2_audio</link></primaryie></indexentry> | 37 | <indexentry><primaryie>struct <link linkend='v4l2-audio'>v4l2_audio</link></primaryie></indexentry> |
38 | <indexentry><primaryie>struct <link linkend='v4l2-audioout'>v4l2_audioout</link></primaryie></indexentry> | 38 | <indexentry><primaryie>struct <link linkend='v4l2-audioout'>v4l2_audioout</link></primaryie></indexentry> |
39 | <indexentry><primaryie>struct <link linkend='v4l2-bt-timings'>v4l2_bt_timings</link></primaryie></indexentry> | ||
39 | <indexentry><primaryie>struct <link linkend='v4l2-buffer'>v4l2_buffer</link></primaryie></indexentry> | 40 | <indexentry><primaryie>struct <link linkend='v4l2-buffer'>v4l2_buffer</link></primaryie></indexentry> |
40 | <indexentry><primaryie>struct <link linkend='v4l2-capability'>v4l2_capability</link></primaryie></indexentry> | 41 | <indexentry><primaryie>struct <link linkend='v4l2-capability'>v4l2_capability</link></primaryie></indexentry> |
41 | <indexentry><primaryie>struct <link linkend='v4l2-captureparm'>v4l2_captureparm</link></primaryie></indexentry> | 42 | <indexentry><primaryie>struct <link linkend='v4l2-captureparm'>v4l2_captureparm</link></primaryie></indexentry> |
@@ -46,6 +47,9 @@ | |||
46 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link></primaryie></indexentry> | 47 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link></primaryie></indexentry> |
47 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-match'>v4l2_dbg_match</link></primaryie></indexentry> | 48 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-match'>v4l2_dbg_match</link></primaryie></indexentry> |
48 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-register'>v4l2_dbg_register</link></primaryie></indexentry> | 49 | <indexentry><primaryie>struct <link linkend='v4l2-dbg-register'>v4l2_dbg_register</link></primaryie></indexentry> |
50 | <indexentry><primaryie>struct <link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link></primaryie></indexentry> | ||
51 | <indexentry><primaryie>struct <link linkend='v4l2-dv-preset'>v4l2_dv_preset</link></primaryie></indexentry> | ||
52 | <indexentry><primaryie>struct <link linkend='v4l2-dv-timings'>v4l2_dv_timings</link></primaryie></indexentry> | ||
49 | <indexentry><primaryie>struct <link linkend='v4l2-enc-idx'>v4l2_enc_idx</link></primaryie></indexentry> | 53 | <indexentry><primaryie>struct <link linkend='v4l2-enc-idx'>v4l2_enc_idx</link></primaryie></indexentry> |
50 | <indexentry><primaryie>struct <link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link></primaryie></indexentry> | 54 | <indexentry><primaryie>struct <link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link></primaryie></indexentry> |
51 | <indexentry><primaryie>struct <link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link></primaryie></indexentry> | 55 | <indexentry><primaryie>struct <link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link></primaryie></indexentry> |
diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl deleted file mode 100644 index 9eba4b7af73d..000000000000 --- a/Documentation/DocBook/procfs-guide.tmpl +++ /dev/null | |||
@@ -1,626 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" | ||
3 | "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ | ||
4 | <!ENTITY procfsexample SYSTEM "procfs_example.xml"> | ||
5 | ]> | ||
6 | |||
7 | <book id="LKProcfsGuide"> | ||
8 | <bookinfo> | ||
9 | <title>Linux Kernel Procfs Guide</title> | ||
10 | |||
11 | <authorgroup> | ||
12 | <author> | ||
13 | <firstname>Erik</firstname> | ||
14 | <othername>(J.A.K.)</othername> | ||
15 | <surname>Mouw</surname> | ||
16 | <affiliation> | ||
17 | <address> | ||
18 | <email>mouw@nl.linux.org</email> | ||
19 | </address> | ||
20 | </affiliation> | ||
21 | </author> | ||
22 | <othercredit> | ||
23 | <contrib> | ||
24 | This software and documentation were written while working on the | ||
25 | LART computing board | ||
26 | (<ulink url="http://www.lartmaker.nl/">http://www.lartmaker.nl/</ulink>), | ||
27 | which was sponsored by the Delt University of Technology projects | ||
28 | Mobile Multi-media Communications and Ubiquitous Communications. | ||
29 | </contrib> | ||
30 | </othercredit> | ||
31 | </authorgroup> | ||
32 | |||
33 | <revhistory> | ||
34 | <revision> | ||
35 | <revnumber>1.0</revnumber> | ||
36 | <date>May 30, 2001</date> | ||
37 | <revremark>Initial revision posted to linux-kernel</revremark> | ||
38 | </revision> | ||
39 | <revision> | ||
40 | <revnumber>1.1</revnumber> | ||
41 | <date>June 3, 2001</date> | ||
42 | <revremark>Revised after comments from linux-kernel</revremark> | ||
43 | </revision> | ||
44 | </revhistory> | ||
45 | |||
46 | <copyright> | ||
47 | <year>2001</year> | ||
48 | <holder>Erik Mouw</holder> | ||
49 | </copyright> | ||
50 | |||
51 | |||
52 | <legalnotice> | ||
53 | <para> | ||
54 | This documentation is free software; you can redistribute it | ||
55 | and/or modify it under the terms of the GNU General Public | ||
56 | License as published by the Free Software Foundation; either | ||
57 | version 2 of the License, or (at your option) any later | ||
58 | version. | ||
59 | </para> | ||
60 | |||
61 | <para> | ||
62 | This documentation is distributed in the hope that it will be | ||
63 | useful, but WITHOUT ANY WARRANTY; without even the implied | ||
64 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
65 | PURPOSE. See the GNU General Public License for more details. | ||
66 | </para> | ||
67 | |||
68 | <para> | ||
69 | You should have received a copy of the GNU General Public | ||
70 | License along with this program; if not, write to the Free | ||
71 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
72 | MA 02111-1307 USA | ||
73 | </para> | ||
74 | |||
75 | <para> | ||
76 | For more details see the file COPYING in the source | ||
77 | distribution of Linux. | ||
78 | </para> | ||
79 | </legalnotice> | ||
80 | </bookinfo> | ||
81 | |||
82 | |||
83 | |||
84 | |||
85 | <toc> | ||
86 | </toc> | ||
87 | |||
88 | |||
89 | |||
90 | |||
91 | <preface id="Preface"> | ||
92 | <title>Preface</title> | ||
93 | |||
94 | <para> | ||
95 | This guide describes the use of the procfs file system from | ||
96 | within the Linux kernel. The idea to write this guide came up on | ||
97 | the #kernelnewbies IRC channel (see <ulink | ||
98 | url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>), | ||
99 | when Jeff Garzik explained the use of procfs and forwarded me a | ||
100 | message Alexander Viro wrote to the linux-kernel mailing list. I | ||
101 | agreed to write it up nicely, so here it is. | ||
102 | </para> | ||
103 | |||
104 | <para> | ||
105 | I'd like to thank Jeff Garzik | ||
106 | <email>jgarzik@pobox.com</email> and Alexander Viro | ||
107 | <email>viro@parcelfarce.linux.theplanet.co.uk</email> for their input, | ||
108 | Tim Waugh <email>twaugh@redhat.com</email> for his <ulink | ||
109 | url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>, | ||
110 | and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for | ||
111 | proofreading. | ||
112 | </para> | ||
113 | |||
114 | <para> | ||
115 | Erik | ||
116 | </para> | ||
117 | </preface> | ||
118 | |||
119 | |||
120 | |||
121 | |||
122 | <chapter id="intro"> | ||
123 | <title>Introduction</title> | ||
124 | |||
125 | <para> | ||
126 | The <filename class="directory">/proc</filename> file system | ||
127 | (procfs) is a special file system in the linux kernel. It's a | ||
128 | virtual file system: it is not associated with a block device | ||
129 | but exists only in memory. The files in the procfs are there to | ||
130 | allow userland programs access to certain information from the | ||
131 | kernel (like process information in <filename | ||
132 | class="directory">/proc/[0-9]+/</filename>), but also for debug | ||
133 | purposes (like <filename>/proc/ksyms</filename>). | ||
134 | </para> | ||
135 | |||
136 | <para> | ||
137 | This guide describes the use of the procfs file system from | ||
138 | within the Linux kernel. It starts by introducing all relevant | ||
139 | functions to manage the files within the file system. After that | ||
140 | it shows how to communicate with userland, and some tips and | ||
141 | tricks will be pointed out. Finally a complete example will be | ||
142 | shown. | ||
143 | </para> | ||
144 | |||
145 | <para> | ||
146 | Note that the files in <filename | ||
147 | class="directory">/proc/sys</filename> are sysctl files: they | ||
148 | don't belong to procfs and are governed by a completely | ||
149 | different API described in the Kernel API book. | ||
150 | </para> | ||
151 | </chapter> | ||
152 | |||
153 | |||
154 | |||
155 | |||
156 | <chapter id="managing"> | ||
157 | <title>Managing procfs entries</title> | ||
158 | |||
159 | <para> | ||
160 | This chapter describes the functions that various kernel | ||
161 | components use to populate the procfs with files, symlinks, | ||
162 | device nodes, and directories. | ||
163 | </para> | ||
164 | |||
165 | <para> | ||
166 | A minor note before we start: if you want to use any of the | ||
167 | procfs functions, be sure to include the correct header file! | ||
168 | This should be one of the first lines in your code: | ||
169 | </para> | ||
170 | |||
171 | <programlisting> | ||
172 | #include <linux/proc_fs.h> | ||
173 | </programlisting> | ||
174 | |||
175 | |||
176 | |||
177 | |||
178 | <sect1 id="regularfile"> | ||
179 | <title>Creating a regular file</title> | ||
180 | |||
181 | <funcsynopsis> | ||
182 | <funcprototype> | ||
183 | <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef> | ||
184 | <paramdef>const char* <parameter>name</parameter></paramdef> | ||
185 | <paramdef>mode_t <parameter>mode</parameter></paramdef> | ||
186 | <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> | ||
187 | </funcprototype> | ||
188 | </funcsynopsis> | ||
189 | |||
190 | <para> | ||
191 | This function creates a regular file with the name | ||
192 | <parameter>name</parameter>, file mode | ||
193 | <parameter>mode</parameter> in the directory | ||
194 | <parameter>parent</parameter>. To create a file in the root of | ||
195 | the procfs, use <constant>NULL</constant> as | ||
196 | <parameter>parent</parameter> parameter. When successful, the | ||
197 | function will return a pointer to the freshly created | ||
198 | <structname>struct proc_dir_entry</structname>; otherwise it | ||
199 | will return <constant>NULL</constant>. <xref | ||
200 | linkend="userland"/> describes how to do something useful with | ||
201 | regular files. | ||
202 | </para> | ||
203 | |||
204 | <para> | ||
205 | Note that it is specifically supported that you can pass a | ||
206 | path that spans multiple directories. For example | ||
207 | <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>) | ||
208 | will create the <filename class="directory">via0</filename> | ||
209 | directory if necessary, with standard | ||
210 | <constant>0755</constant> permissions. | ||
211 | </para> | ||
212 | |||
213 | <para> | ||
214 | If you only want to be able to read the file, the function | ||
215 | <function>create_proc_read_entry</function> described in <xref | ||
216 | linkend="convenience"/> may be used to create and initialise | ||
217 | the procfs entry in one single call. | ||
218 | </para> | ||
219 | </sect1> | ||
220 | |||
221 | |||
222 | |||
223 | |||
224 | <sect1 id="Creating_a_symlink"> | ||
225 | <title>Creating a symlink</title> | ||
226 | |||
227 | <funcsynopsis> | ||
228 | <funcprototype> | ||
229 | <funcdef>struct proc_dir_entry* | ||
230 | <function>proc_symlink</function></funcdef> <paramdef>const | ||
231 | char* <parameter>name</parameter></paramdef> | ||
232 | <paramdef>struct proc_dir_entry* | ||
233 | <parameter>parent</parameter></paramdef> <paramdef>const | ||
234 | char* <parameter>dest</parameter></paramdef> | ||
235 | </funcprototype> | ||
236 | </funcsynopsis> | ||
237 | |||
238 | <para> | ||
239 | This creates a symlink in the procfs directory | ||
240 | <parameter>parent</parameter> that points from | ||
241 | <parameter>name</parameter> to | ||
242 | <parameter>dest</parameter>. This translates in userland to | ||
243 | <literal>ln -s</literal> <parameter>dest</parameter> | ||
244 | <parameter>name</parameter>. | ||
245 | </para> | ||
246 | </sect1> | ||
247 | |||
248 | <sect1 id="Creating_a_directory"> | ||
249 | <title>Creating a directory</title> | ||
250 | |||
251 | <funcsynopsis> | ||
252 | <funcprototype> | ||
253 | <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef> | ||
254 | <paramdef>const char* <parameter>name</parameter></paramdef> | ||
255 | <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> | ||
256 | </funcprototype> | ||
257 | </funcsynopsis> | ||
258 | |||
259 | <para> | ||
260 | Create a directory <parameter>name</parameter> in the procfs | ||
261 | directory <parameter>parent</parameter>. | ||
262 | </para> | ||
263 | </sect1> | ||
264 | |||
265 | |||
266 | |||
267 | |||
268 | <sect1 id="Removing_an_entry"> | ||
269 | <title>Removing an entry</title> | ||
270 | |||
271 | <funcsynopsis> | ||
272 | <funcprototype> | ||
273 | <funcdef>void <function>remove_proc_entry</function></funcdef> | ||
274 | <paramdef>const char* <parameter>name</parameter></paramdef> | ||
275 | <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> | ||
276 | </funcprototype> | ||
277 | </funcsynopsis> | ||
278 | |||
279 | <para> | ||
280 | Removes the entry <parameter>name</parameter> in the directory | ||
281 | <parameter>parent</parameter> from the procfs. Entries are | ||
282 | removed by their <emphasis>name</emphasis>, not by the | ||
283 | <structname>struct proc_dir_entry</structname> returned by the | ||
284 | various create functions. Note that this function doesn't | ||
285 | recursively remove entries. | ||
286 | </para> | ||
287 | |||
288 | <para> | ||
289 | Be sure to free the <structfield>data</structfield> entry from | ||
290 | the <structname>struct proc_dir_entry</structname> before | ||
291 | <function>remove_proc_entry</function> is called (that is: if | ||
292 | there was some <structfield>data</structfield> allocated, of | ||
293 | course). See <xref linkend="usingdata"/> for more information | ||
294 | on using the <structfield>data</structfield> entry. | ||
295 | </para> | ||
296 | </sect1> | ||
297 | </chapter> | ||
298 | |||
299 | |||
300 | |||
301 | |||
302 | <chapter id="userland"> | ||
303 | <title>Communicating with userland</title> | ||
304 | |||
305 | <para> | ||
306 | Instead of reading (or writing) information directly from | ||
307 | kernel memory, procfs works with <emphasis>call back | ||
308 | functions</emphasis> for files: functions that are called when | ||
309 | a specific file is being read or written. Such functions have | ||
310 | to be initialised after the procfs file is created by setting | ||
311 | the <structfield>read_proc</structfield> and/or | ||
312 | <structfield>write_proc</structfield> fields in the | ||
313 | <structname>struct proc_dir_entry*</structname> that the | ||
314 | function <function>create_proc_entry</function> returned: | ||
315 | </para> | ||
316 | |||
317 | <programlisting> | ||
318 | struct proc_dir_entry* entry; | ||
319 | |||
320 | entry->read_proc = read_proc_foo; | ||
321 | entry->write_proc = write_proc_foo; | ||
322 | </programlisting> | ||
323 | |||
324 | <para> | ||
325 | If you only want to use a the | ||
326 | <structfield>read_proc</structfield>, the function | ||
327 | <function>create_proc_read_entry</function> described in <xref | ||
328 | linkend="convenience"/> may be used to create and initialise the | ||
329 | procfs entry in one single call. | ||
330 | </para> | ||
331 | |||
332 | |||
333 | |||
334 | <sect1 id="Reading_data"> | ||
335 | <title>Reading data</title> | ||
336 | |||
337 | <para> | ||
338 | The read function is a call back function that allows userland | ||
339 | processes to read data from the kernel. The read function | ||
340 | should have the following format: | ||
341 | </para> | ||
342 | |||
343 | <funcsynopsis> | ||
344 | <funcprototype> | ||
345 | <funcdef>int <function>read_func</function></funcdef> | ||
346 | <paramdef>char* <parameter>buffer</parameter></paramdef> | ||
347 | <paramdef>char** <parameter>start</parameter></paramdef> | ||
348 | <paramdef>off_t <parameter>off</parameter></paramdef> | ||
349 | <paramdef>int <parameter>count</parameter></paramdef> | ||
350 | <paramdef>int* <parameter>peof</parameter></paramdef> | ||
351 | <paramdef>void* <parameter>data</parameter></paramdef> | ||
352 | </funcprototype> | ||
353 | </funcsynopsis> | ||
354 | |||
355 | <para> | ||
356 | The read function should write its information into the | ||
357 | <parameter>buffer</parameter>, which will be exactly | ||
358 | <literal>PAGE_SIZE</literal> bytes long. | ||
359 | </para> | ||
360 | |||
361 | <para> | ||
362 | The parameter | ||
363 | <parameter>peof</parameter> should be used to signal that the | ||
364 | end of the file has been reached by writing | ||
365 | <literal>1</literal> to the memory location | ||
366 | <parameter>peof</parameter> points to. | ||
367 | </para> | ||
368 | |||
369 | <para> | ||
370 | The <parameter>data</parameter> | ||
371 | parameter can be used to create a single call back function for | ||
372 | several files, see <xref linkend="usingdata"/>. | ||
373 | </para> | ||
374 | |||
375 | <para> | ||
376 | The rest of the parameters and the return value are described | ||
377 | by a comment in <filename>fs/proc/generic.c</filename> as follows: | ||
378 | </para> | ||
379 | |||
380 | <blockquote> | ||
381 | <para> | ||
382 | You have three ways to return data: | ||
383 | </para> | ||
384 | <orderedlist> | ||
385 | <listitem> | ||
386 | <para> | ||
387 | Leave <literal>*start = NULL</literal>. (This is the default.) | ||
388 | Put the data of the requested offset at that | ||
389 | offset within the buffer. Return the number (<literal>n</literal>) | ||
390 | of bytes there are from the beginning of the | ||
391 | buffer up to the last byte of data. If the | ||
392 | number of supplied bytes (<literal>= n - offset</literal>) is | ||
393 | greater than zero and you didn't signal eof | ||
394 | and the reader is prepared to take more data | ||
395 | you will be called again with the requested | ||
396 | offset advanced by the number of bytes | ||
397 | absorbed. This interface is useful for files | ||
398 | no larger than the buffer. | ||
399 | </para> | ||
400 | </listitem> | ||
401 | <listitem> | ||
402 | <para> | ||
403 | Set <literal>*start</literal> to an unsigned long value less than | ||
404 | the buffer address but greater than zero. | ||
405 | Put the data of the requested offset at the | ||
406 | beginning of the buffer. Return the number of | ||
407 | bytes of data placed there. If this number is | ||
408 | greater than zero and you didn't signal eof | ||
409 | and the reader is prepared to take more data | ||
410 | you will be called again with the requested | ||
411 | offset advanced by <literal>*start</literal>. This interface is | ||
412 | useful when you have a large file consisting | ||
413 | of a series of blocks which you want to count | ||
414 | and return as wholes. | ||
415 | (Hack by Paul.Russell@rustcorp.com.au) | ||
416 | </para> | ||
417 | </listitem> | ||
418 | <listitem> | ||
419 | <para> | ||
420 | Set <literal>*start</literal> to an address within the buffer. | ||
421 | Put the data of the requested offset at <literal>*start</literal>. | ||
422 | Return the number of bytes of data placed there. | ||
423 | If this number is greater than zero and you | ||
424 | didn't signal eof and the reader is prepared to | ||
425 | take more data you will be called again with the | ||
426 | requested offset advanced by the number of bytes | ||
427 | absorbed. | ||
428 | </para> | ||
429 | </listitem> | ||
430 | </orderedlist> | ||
431 | </blockquote> | ||
432 | |||
433 | <para> | ||
434 | <xref linkend="example"/> shows how to use a read call back | ||
435 | function. | ||
436 | </para> | ||
437 | </sect1> | ||
438 | |||
439 | |||
440 | |||
441 | |||
442 | <sect1 id="Writing_data"> | ||
443 | <title>Writing data</title> | ||
444 | |||
445 | <para> | ||
446 | The write call back function allows a userland process to write | ||
447 | data to the kernel, so it has some kind of control over the | ||
448 | kernel. The write function should have the following format: | ||
449 | </para> | ||
450 | |||
451 | <funcsynopsis> | ||
452 | <funcprototype> | ||
453 | <funcdef>int <function>write_func</function></funcdef> | ||
454 | <paramdef>struct file* <parameter>file</parameter></paramdef> | ||
455 | <paramdef>const char* <parameter>buffer</parameter></paramdef> | ||
456 | <paramdef>unsigned long <parameter>count</parameter></paramdef> | ||
457 | <paramdef>void* <parameter>data</parameter></paramdef> | ||
458 | </funcprototype> | ||
459 | </funcsynopsis> | ||
460 | |||
461 | <para> | ||
462 | The write function should read <parameter>count</parameter> | ||
463 | bytes at maximum from the <parameter>buffer</parameter>. Note | ||
464 | that the <parameter>buffer</parameter> doesn't live in the | ||
465 | kernel's memory space, so it should first be copied to kernel | ||
466 | space with <function>copy_from_user</function>. The | ||
467 | <parameter>file</parameter> parameter is usually | ||
468 | ignored. <xref linkend="usingdata"/> shows how to use the | ||
469 | <parameter>data</parameter> parameter. | ||
470 | </para> | ||
471 | |||
472 | <para> | ||
473 | Again, <xref linkend="example"/> shows how to use this call back | ||
474 | function. | ||
475 | </para> | ||
476 | </sect1> | ||
477 | |||
478 | |||
479 | |||
480 | |||
481 | <sect1 id="usingdata"> | ||
482 | <title>A single call back for many files</title> | ||
483 | |||
484 | <para> | ||
485 | When a large number of almost identical files is used, it's | ||
486 | quite inconvenient to use a separate call back function for | ||
487 | each file. A better approach is to have a single call back | ||
488 | function that distinguishes between the files by using the | ||
489 | <structfield>data</structfield> field in <structname>struct | ||
490 | proc_dir_entry</structname>. First of all, the | ||
491 | <structfield>data</structfield> field has to be initialised: | ||
492 | </para> | ||
493 | |||
494 | <programlisting> | ||
495 | struct proc_dir_entry* entry; | ||
496 | struct my_file_data *file_data; | ||
497 | |||
498 | file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL); | ||
499 | entry->data = file_data; | ||
500 | </programlisting> | ||
501 | |||
502 | <para> | ||
503 | The <structfield>data</structfield> field is a <type>void | ||
504 | *</type>, so it can be initialised with anything. | ||
505 | </para> | ||
506 | |||
507 | <para> | ||
508 | Now that the <structfield>data</structfield> field is set, the | ||
509 | <function>read_proc</function> and | ||
510 | <function>write_proc</function> can use it to distinguish | ||
511 | between files because they get it passed into their | ||
512 | <parameter>data</parameter> parameter: | ||
513 | </para> | ||
514 | |||
515 | <programlisting> | ||
516 | int foo_read_func(char *page, char **start, off_t off, | ||
517 | int count, int *eof, void *data) | ||
518 | { | ||
519 | int len; | ||
520 | |||
521 | if(data == file_data) { | ||
522 | /* special case for this file */ | ||
523 | } else { | ||
524 | /* normal processing */ | ||
525 | } | ||
526 | |||
527 | return len; | ||
528 | } | ||
529 | </programlisting> | ||
530 | |||
531 | <para> | ||
532 | Be sure to free the <structfield>data</structfield> data field | ||
533 | when removing the procfs entry. | ||
534 | </para> | ||
535 | </sect1> | ||
536 | </chapter> | ||
537 | |||
538 | |||
539 | |||
540 | |||
541 | <chapter id="tips"> | ||
542 | <title>Tips and tricks</title> | ||
543 | |||
544 | |||
545 | |||
546 | |||
547 | <sect1 id="convenience"> | ||
548 | <title>Convenience functions</title> | ||
549 | |||
550 | <funcsynopsis> | ||
551 | <funcprototype> | ||
552 | <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef> | ||
553 | <paramdef>const char* <parameter>name</parameter></paramdef> | ||
554 | <paramdef>mode_t <parameter>mode</parameter></paramdef> | ||
555 | <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> | ||
556 | <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef> | ||
557 | <paramdef>void* <parameter>data</parameter></paramdef> | ||
558 | </funcprototype> | ||
559 | </funcsynopsis> | ||
560 | |||
561 | <para> | ||
562 | This function creates a regular file in exactly the same way | ||
563 | as <function>create_proc_entry</function> from <xref | ||
564 | linkend="regularfile"/> does, but also allows to set the read | ||
565 | function <parameter>read_proc</parameter> in one call. This | ||
566 | function can set the <parameter>data</parameter> as well, like | ||
567 | explained in <xref linkend="usingdata"/>. | ||
568 | </para> | ||
569 | </sect1> | ||
570 | |||
571 | |||
572 | |||
573 | <sect1 id="Modules"> | ||
574 | <title>Modules</title> | ||
575 | |||
576 | <para> | ||
577 | If procfs is being used from within a module, be sure to set | ||
578 | the <structfield>owner</structfield> field in the | ||
579 | <structname>struct proc_dir_entry</structname> to | ||
580 | <constant>THIS_MODULE</constant>. | ||
581 | </para> | ||
582 | |||
583 | <programlisting> | ||
584 | struct proc_dir_entry* entry; | ||
585 | |||
586 | entry->owner = THIS_MODULE; | ||
587 | </programlisting> | ||
588 | </sect1> | ||
589 | |||
590 | |||
591 | |||
592 | |||
593 | <sect1 id="Mode_and_ownership"> | ||
594 | <title>Mode and ownership</title> | ||
595 | |||
596 | <para> | ||
597 | Sometimes it is useful to change the mode and/or ownership of | ||
598 | a procfs entry. Here is an example that shows how to achieve | ||
599 | that: | ||
600 | </para> | ||
601 | |||
602 | <programlisting> | ||
603 | struct proc_dir_entry* entry; | ||
604 | |||
605 | entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH; | ||
606 | entry->uid = 0; | ||
607 | entry->gid = 100; | ||
608 | </programlisting> | ||
609 | |||
610 | </sect1> | ||
611 | </chapter> | ||
612 | |||
613 | |||
614 | |||
615 | |||
616 | <chapter id="example"> | ||
617 | <title>Example</title> | ||
618 | |||
619 | <!-- be careful with the example code: it shouldn't be wider than | ||
620 | approx. 60 columns, or otherwise it won't fit properly on a page | ||
621 | --> | ||
622 | |||
623 | &procfsexample; | ||
624 | |||
625 | </chapter> | ||
626 | </book> | ||
diff --git a/Documentation/DocBook/procfs_example.c b/Documentation/DocBook/procfs_example.c deleted file mode 100644 index a5b11793b1e0..000000000000 --- a/Documentation/DocBook/procfs_example.c +++ /dev/null | |||
@@ -1,201 +0,0 @@ | |||
1 | /* | ||
2 | * procfs_example.c: an example proc interface | ||
3 | * | ||
4 | * Copyright (C) 2001, Erik Mouw (mouw@nl.linux.org) | ||
5 | * | ||
6 | * This file accompanies the procfs-guide in the Linux kernel | ||
7 | * source. Its main use is to demonstrate the concepts and | ||
8 | * functions described in the guide. | ||
9 | * | ||
10 | * This software has been developed while working on the LART | ||
11 | * computing board (http://www.lartmaker.nl), which was sponsored | ||
12 | * by the Delt University of Technology projects Mobile Multi-media | ||
13 | * Communications and Ubiquitous Communications. | ||
14 | * | ||
15 | * This program is free software; you can redistribute | ||
16 | * it and/or modify it under the terms of the GNU General | ||
17 | * Public License as published by the Free Software | ||
18 | * Foundation; either version 2 of the License, or (at your | ||
19 | * option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be | ||
22 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
23 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
24 | * PURPOSE. See the GNU General Public License for more | ||
25 | * details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public | ||
28 | * License along with this program; if not, write to the | ||
29 | * Free Software Foundation, Inc., 59 Temple Place, | ||
30 | * Suite 330, Boston, MA 02111-1307 USA | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/proc_fs.h> | ||
38 | #include <linux/jiffies.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | |||
42 | #define MODULE_VERS "1.0" | ||
43 | #define MODULE_NAME "procfs_example" | ||
44 | |||
45 | #define FOOBAR_LEN 8 | ||
46 | |||
47 | struct fb_data_t { | ||
48 | char name[FOOBAR_LEN + 1]; | ||
49 | char value[FOOBAR_LEN + 1]; | ||
50 | }; | ||
51 | |||
52 | |||
53 | static struct proc_dir_entry *example_dir, *foo_file, | ||
54 | *bar_file, *jiffies_file, *symlink; | ||
55 | |||
56 | |||
57 | struct fb_data_t foo_data, bar_data; | ||
58 | |||
59 | |||
60 | static int proc_read_jiffies(char *page, char **start, | ||
61 | off_t off, int count, | ||
62 | int *eof, void *data) | ||
63 | { | ||
64 | int len; | ||
65 | |||
66 | len = sprintf(page, "jiffies = %ld\n", | ||
67 | jiffies); | ||
68 | |||
69 | return len; | ||
70 | } | ||
71 | |||
72 | |||
73 | static int proc_read_foobar(char *page, char **start, | ||
74 | off_t off, int count, | ||
75 | int *eof, void *data) | ||
76 | { | ||
77 | int len; | ||
78 | struct fb_data_t *fb_data = (struct fb_data_t *)data; | ||
79 | |||
80 | /* DON'T DO THAT - buffer overruns are bad */ | ||
81 | len = sprintf(page, "%s = '%s'\n", | ||
82 | fb_data->name, fb_data->value); | ||
83 | |||
84 | return len; | ||
85 | } | ||
86 | |||
87 | |||
88 | static int proc_write_foobar(struct file *file, | ||
89 | const char *buffer, | ||
90 | unsigned long count, | ||
91 | void *data) | ||
92 | { | ||
93 | int len; | ||
94 | struct fb_data_t *fb_data = (struct fb_data_t *)data; | ||
95 | |||
96 | if(count > FOOBAR_LEN) | ||
97 | len = FOOBAR_LEN; | ||
98 | else | ||
99 | len = count; | ||
100 | |||
101 | if(copy_from_user(fb_data->value, buffer, len)) | ||
102 | return -EFAULT; | ||
103 | |||
104 | fb_data->value[len] = '\0'; | ||
105 | |||
106 | return len; | ||
107 | } | ||
108 | |||
109 | |||
110 | static int __init init_procfs_example(void) | ||
111 | { | ||
112 | int rv = 0; | ||
113 | |||
114 | /* create directory */ | ||
115 | example_dir = proc_mkdir(MODULE_NAME, NULL); | ||
116 | if(example_dir == NULL) { | ||
117 | rv = -ENOMEM; | ||
118 | goto out; | ||
119 | } | ||
120 | /* create jiffies using convenience function */ | ||
121 | jiffies_file = create_proc_read_entry("jiffies", | ||
122 | 0444, example_dir, | ||
123 | proc_read_jiffies, | ||
124 | NULL); | ||
125 | if(jiffies_file == NULL) { | ||
126 | rv = -ENOMEM; | ||
127 | goto no_jiffies; | ||
128 | } | ||
129 | |||
130 | /* create foo and bar files using same callback | ||
131 | * functions | ||
132 | */ | ||
133 | foo_file = create_proc_entry("foo", 0644, example_dir); | ||
134 | if(foo_file == NULL) { | ||
135 | rv = -ENOMEM; | ||
136 | goto no_foo; | ||
137 | } | ||
138 | |||
139 | strcpy(foo_data.name, "foo"); | ||
140 | strcpy(foo_data.value, "foo"); | ||
141 | foo_file->data = &foo_data; | ||
142 | foo_file->read_proc = proc_read_foobar; | ||
143 | foo_file->write_proc = proc_write_foobar; | ||
144 | |||
145 | bar_file = create_proc_entry("bar", 0644, example_dir); | ||
146 | if(bar_file == NULL) { | ||
147 | rv = -ENOMEM; | ||
148 | goto no_bar; | ||
149 | } | ||
150 | |||
151 | strcpy(bar_data.name, "bar"); | ||
152 | strcpy(bar_data.value, "bar"); | ||
153 | bar_file->data = &bar_data; | ||
154 | bar_file->read_proc = proc_read_foobar; | ||
155 | bar_file->write_proc = proc_write_foobar; | ||
156 | |||
157 | /* create symlink */ | ||
158 | symlink = proc_symlink("jiffies_too", example_dir, | ||
159 | "jiffies"); | ||
160 | if(symlink == NULL) { | ||
161 | rv = -ENOMEM; | ||
162 | goto no_symlink; | ||
163 | } | ||
164 | |||
165 | /* everything OK */ | ||
166 | printk(KERN_INFO "%s %s initialised\n", | ||
167 | MODULE_NAME, MODULE_VERS); | ||
168 | return 0; | ||
169 | |||
170 | no_symlink: | ||
171 | remove_proc_entry("bar", example_dir); | ||
172 | no_bar: | ||
173 | remove_proc_entry("foo", example_dir); | ||
174 | no_foo: | ||
175 | remove_proc_entry("jiffies", example_dir); | ||
176 | no_jiffies: | ||
177 | remove_proc_entry(MODULE_NAME, NULL); | ||
178 | out: | ||
179 | return rv; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void __exit cleanup_procfs_example(void) | ||
184 | { | ||
185 | remove_proc_entry("jiffies_too", example_dir); | ||
186 | remove_proc_entry("bar", example_dir); | ||
187 | remove_proc_entry("foo", example_dir); | ||
188 | remove_proc_entry("jiffies", example_dir); | ||
189 | remove_proc_entry(MODULE_NAME, NULL); | ||
190 | |||
191 | printk(KERN_INFO "%s %s removed\n", | ||
192 | MODULE_NAME, MODULE_VERS); | ||
193 | } | ||
194 | |||
195 | |||
196 | module_init(init_procfs_example); | ||
197 | module_exit(cleanup_procfs_example); | ||
198 | |||
199 | MODULE_AUTHOR("Erik Mouw"); | ||
200 | MODULE_DESCRIPTION("procfs examples"); | ||
201 | MODULE_LICENSE("GPL"); | ||
diff --git a/Documentation/DocBook/v4l/common.xml b/Documentation/DocBook/v4l/common.xml index b1a81d246d58..c65f0ac9b6ee 100644 --- a/Documentation/DocBook/v4l/common.xml +++ b/Documentation/DocBook/v4l/common.xml | |||
@@ -716,6 +716,41 @@ if (-1 == ioctl (fd, &VIDIOC-S-STD;, &std_id)) { | |||
716 | } | 716 | } |
717 | </programlisting> | 717 | </programlisting> |
718 | </example> | 718 | </example> |
719 | <section id="dv-timings"> | ||
720 | <title>Digital Video (DV) Timings</title> | ||
721 | <para> | ||
722 | The video standards discussed so far has been dealing with Analog TV and the | ||
723 | corresponding video timings. Today there are many more different hardware interfaces | ||
724 | such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry | ||
725 | video signals and there is a need to extend the API to select the video timings | ||
726 | for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to | ||
727 | the limited bits available, a new set of IOCTLs is added to set/get video timings at | ||
728 | the input and output: </para><itemizedlist> | ||
729 | <listitem> | ||
730 | <para>DV Presets: Digital Video (DV) presets. These are IDs representing a | ||
731 | video timing at the input/output. Presets are pre-defined timings implemented | ||
732 | by the hardware according to video standards. A __u32 data type is used to represent | ||
733 | a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions | ||
734 | to support as many different presets as needed.</para> | ||
735 | </listitem> | ||
736 | <listitem> | ||
737 | <para>Custom DV Timings: This will allow applications to define more detailed | ||
738 | custom video timings for the interface. This includes parameters such as width, height, | ||
739 | polarities, frontporch, backporch etc. | ||
740 | </para> | ||
741 | </listitem> | ||
742 | </itemizedlist> | ||
743 | <para>To enumerate and query the attributes of DV presets supported by a device, | ||
744 | applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset, | ||
745 | applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the | ||
746 | &VIDIOC-S-DV-PRESET; ioctl.</para> | ||
747 | <para>To set custom DV timings for the device, applications use the | ||
748 | &VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the | ||
749 | &VIDIOC-G-DV-TIMINGS; ioctl.</para> | ||
750 | <para>Applications can make use of the <xref linkend="input-capabilities" /> and | ||
751 | <xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the | ||
752 | video timings for the device.</para> | ||
753 | </section> | ||
719 | </section> | 754 | </section> |
720 | 755 | ||
721 | &sub-controls; | 756 | &sub-controls; |
diff --git a/Documentation/DocBook/v4l/compat.xml b/Documentation/DocBook/v4l/compat.xml index 4d1902a54d61..b9dbdf9e6d29 100644 --- a/Documentation/DocBook/v4l/compat.xml +++ b/Documentation/DocBook/v4l/compat.xml | |||
@@ -2291,8 +2291,8 @@ was renamed to <structname id="v4l2-chip-ident-old">v4l2_chip_ident_old</structn | |||
2291 | <listitem> | 2291 | <listitem> |
2292 | <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para> | 2292 | <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para> |
2293 | </listitem> | 2293 | </listitem> |
2294 | </orderedlist> | 2294 | </orderedlist> |
2295 | </section> | 2295 | </section> |
2296 | <section> | 2296 | <section> |
2297 | <title>V4L2 in Linux 2.6.32</title> | 2297 | <title>V4L2 in Linux 2.6.32</title> |
2298 | <orderedlist> | 2298 | <orderedlist> |
@@ -2322,8 +2322,16 @@ more information.</para> | |||
2322 | <listitem> | 2322 | <listitem> |
2323 | <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para> | 2323 | <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para> |
2324 | </listitem> | 2324 | </listitem> |
2325 | </orderedlist> | 2325 | </orderedlist> |
2326 | </section> | 2326 | </section> |
2327 | <section> | ||
2328 | <title>V4L2 in Linux 2.6.33</title> | ||
2329 | <orderedlist> | ||
2330 | <listitem> | ||
2331 | <para>Added support for Digital Video timings in order to support HDTV receivers and transmitters.</para> | ||
2332 | </listitem> | ||
2333 | </orderedlist> | ||
2334 | </section> | ||
2327 | </section> | 2335 | </section> |
2328 | 2336 | ||
2329 | <section id="other"> | 2337 | <section id="other"> |
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml index 937b4157a5d0..060105af49e5 100644 --- a/Documentation/DocBook/v4l/v4l2.xml +++ b/Documentation/DocBook/v4l/v4l2.xml | |||
@@ -74,6 +74,17 @@ Remote Controller chapter.</contrib> | |||
74 | </address> | 74 | </address> |
75 | </affiliation> | 75 | </affiliation> |
76 | </author> | 76 | </author> |
77 | |||
78 | <author> | ||
79 | <firstname>Muralidharan</firstname> | ||
80 | <surname>Karicheri</surname> | ||
81 | <contrib>Documented the Digital Video timings API.</contrib> | ||
82 | <affiliation> | ||
83 | <address> | ||
84 | <email>m-karicheri2@ti.com</email> | ||
85 | </address> | ||
86 | </affiliation> | ||
87 | </author> | ||
77 | </authorgroup> | 88 | </authorgroup> |
78 | 89 | ||
79 | <copyright> | 90 | <copyright> |
@@ -89,7 +100,7 @@ Remote Controller chapter.</contrib> | |||
89 | <year>2008</year> | 100 | <year>2008</year> |
90 | <year>2009</year> | 101 | <year>2009</year> |
91 | <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin | 102 | <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin |
92 | Rubli, Andy Walls, Mauro Carvalho Chehab</holder> | 103 | Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder> |
93 | </copyright> | 104 | </copyright> |
94 | <legalnotice> | 105 | <legalnotice> |
95 | <para>Except when explicitly stated as GPL, programming examples within | 106 | <para>Except when explicitly stated as GPL, programming examples within |
@@ -103,6 +114,13 @@ structs, ioctls) must be noted in more detail in the history chapter | |||
103 | applications. --> | 114 | applications. --> |
104 | 115 | ||
105 | <revision> | 116 | <revision> |
117 | <revnumber>2.6.33</revnumber> | ||
118 | <date>2009-12-03</date> | ||
119 | <authorinitials>mk</authorinitials> | ||
120 | <revremark>Added documentation for the Digital Video timings API.</revremark> | ||
121 | </revision> | ||
122 | |||
123 | <revision> | ||
106 | <revnumber>2.6.32</revnumber> | 124 | <revnumber>2.6.32</revnumber> |
107 | <date>2009-08-31</date> | 125 | <date>2009-08-31</date> |
108 | <authorinitials>mcc</authorinitials> | 126 | <authorinitials>mcc</authorinitials> |
@@ -355,7 +373,7 @@ and discussions on the V4L mailing list.</revremark> | |||
355 | </partinfo> | 373 | </partinfo> |
356 | 374 | ||
357 | <title>Video for Linux Two API Specification</title> | 375 | <title>Video for Linux Two API Specification</title> |
358 | <subtitle>Revision 2.6.32</subtitle> | 376 | <subtitle>Revision 2.6.33</subtitle> |
359 | 377 | ||
360 | <chapter id="common"> | 378 | <chapter id="common"> |
361 | &sub-common; | 379 | &sub-common; |
@@ -411,6 +429,7 @@ and discussions on the V4L mailing list.</revremark> | |||
411 | &sub-encoder-cmd; | 429 | &sub-encoder-cmd; |
412 | &sub-enumaudio; | 430 | &sub-enumaudio; |
413 | &sub-enumaudioout; | 431 | &sub-enumaudioout; |
432 | &sub-enum-dv-presets; | ||
414 | &sub-enum-fmt; | 433 | &sub-enum-fmt; |
415 | &sub-enum-framesizes; | 434 | &sub-enum-framesizes; |
416 | &sub-enum-frameintervals; | 435 | &sub-enum-frameintervals; |
@@ -421,6 +440,8 @@ and discussions on the V4L mailing list.</revremark> | |||
421 | &sub-g-audioout; | 440 | &sub-g-audioout; |
422 | &sub-g-crop; | 441 | &sub-g-crop; |
423 | &sub-g-ctrl; | 442 | &sub-g-ctrl; |
443 | &sub-g-dv-preset; | ||
444 | &sub-g-dv-timings; | ||
424 | &sub-g-enc-index; | 445 | &sub-g-enc-index; |
425 | &sub-g-ext-ctrls; | 446 | &sub-g-ext-ctrls; |
426 | &sub-g-fbuf; | 447 | &sub-g-fbuf; |
@@ -441,6 +462,7 @@ and discussions on the V4L mailing list.</revremark> | |||
441 | &sub-querybuf; | 462 | &sub-querybuf; |
442 | &sub-querycap; | 463 | &sub-querycap; |
443 | &sub-queryctrl; | 464 | &sub-queryctrl; |
465 | &sub-query-dv-preset; | ||
444 | &sub-querystd; | 466 | &sub-querystd; |
445 | &sub-reqbufs; | 467 | &sub-reqbufs; |
446 | &sub-s-hw-freq-seek; | 468 | &sub-s-hw-freq-seek; |
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml index 3e282ed9f593..068325940658 100644 --- a/Documentation/DocBook/v4l/videodev2.h.xml +++ b/Documentation/DocBook/v4l/videodev2.h.xml | |||
@@ -734,6 +734,99 @@ struct <link linkend="v4l2-standard">v4l2_standard</link> { | |||
734 | }; | 734 | }; |
735 | 735 | ||
736 | /* | 736 | /* |
737 | * V I D E O T I M I N G S D V P R E S E T | ||
738 | */ | ||
739 | struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link> { | ||
740 | __u32 preset; | ||
741 | __u32 reserved[4]; | ||
742 | }; | ||
743 | |||
744 | /* | ||
745 | * D V P R E S E T S E N U M E R A T I O N | ||
746 | */ | ||
747 | struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link> { | ||
748 | __u32 index; | ||
749 | __u32 preset; | ||
750 | __u8 name[32]; /* Name of the preset timing */ | ||
751 | __u32 width; | ||
752 | __u32 height; | ||
753 | __u32 reserved[4]; | ||
754 | }; | ||
755 | |||
756 | /* | ||
757 | * D V P R E S E T V A L U E S | ||
758 | */ | ||
759 | #define V4L2_DV_INVALID 0 | ||
760 | #define V4L2_DV_480P59_94 1 /* BT.1362 */ | ||
761 | #define V4L2_DV_576P50 2 /* BT.1362 */ | ||
762 | #define V4L2_DV_720P24 3 /* SMPTE 296M */ | ||
763 | #define V4L2_DV_720P25 4 /* SMPTE 296M */ | ||
764 | #define V4L2_DV_720P30 5 /* SMPTE 296M */ | ||
765 | #define V4L2_DV_720P50 6 /* SMPTE 296M */ | ||
766 | #define V4L2_DV_720P59_94 7 /* SMPTE 274M */ | ||
767 | #define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ | ||
768 | #define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ | ||
769 | #define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ | ||
770 | #define V4L2_DV_1080I25 11 /* BT.1120 */ | ||
771 | #define V4L2_DV_1080I50 12 /* SMPTE 296M */ | ||
772 | #define V4L2_DV_1080I60 13 /* SMPTE 296M */ | ||
773 | #define V4L2_DV_1080P24 14 /* SMPTE 296M */ | ||
774 | #define V4L2_DV_1080P25 15 /* SMPTE 296M */ | ||
775 | #define V4L2_DV_1080P30 16 /* SMPTE 296M */ | ||
776 | #define V4L2_DV_1080P50 17 /* BT.1120 */ | ||
777 | #define V4L2_DV_1080P60 18 /* BT.1120 */ | ||
778 | |||
779 | /* | ||
780 | * D V B T T I M I N G S | ||
781 | */ | ||
782 | |||
783 | /* BT.656/BT.1120 timing data */ | ||
784 | struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link> { | ||
785 | __u32 width; /* width in pixels */ | ||
786 | __u32 height; /* height in lines */ | ||
787 | __u32 interlaced; /* Interlaced or progressive */ | ||
788 | __u32 polarities; /* Positive or negative polarity */ | ||
789 | __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ | ||
790 | __u32 hfrontporch; /* Horizpontal front porch in pixels */ | ||
791 | __u32 hsync; /* Horizontal Sync length in pixels */ | ||
792 | __u32 hbackporch; /* Horizontal back porch in pixels */ | ||
793 | __u32 vfrontporch; /* Vertical front porch in pixels */ | ||
794 | __u32 vsync; /* Vertical Sync length in lines */ | ||
795 | __u32 vbackporch; /* Vertical back porch in lines */ | ||
796 | __u32 il_vfrontporch; /* Vertical front porch for bottom field of | ||
797 | * interlaced field formats | ||
798 | */ | ||
799 | __u32 il_vsync; /* Vertical sync length for bottom field of | ||
800 | * interlaced field formats | ||
801 | */ | ||
802 | __u32 il_vbackporch; /* Vertical back porch for bottom field of | ||
803 | * interlaced field formats | ||
804 | */ | ||
805 | __u32 reserved[16]; | ||
806 | } __attribute__ ((packed)); | ||
807 | |||
808 | /* Interlaced or progressive format */ | ||
809 | #define V4L2_DV_PROGRESSIVE 0 | ||
810 | #define V4L2_DV_INTERLACED 1 | ||
811 | |||
812 | /* Polarities. If bit is not set, it is assumed to be negative polarity */ | ||
813 | #define V4L2_DV_VSYNC_POS_POL 0x00000001 | ||
814 | #define V4L2_DV_HSYNC_POS_POL 0x00000002 | ||
815 | |||
816 | |||
817 | /* DV timings */ | ||
818 | struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link> { | ||
819 | __u32 type; | ||
820 | union { | ||
821 | struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link> bt; | ||
822 | __u32 reserved[32]; | ||
823 | }; | ||
824 | } __attribute__ ((packed)); | ||
825 | |||
826 | /* Values for the type field */ | ||
827 | #define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ | ||
828 | |||
829 | /* | ||
737 | * V I D E O I N P U T S | 830 | * V I D E O I N P U T S |
738 | */ | 831 | */ |
739 | struct <link linkend="v4l2-input">v4l2_input</link> { | 832 | struct <link linkend="v4l2-input">v4l2_input</link> { |
@@ -744,7 +837,8 @@ struct <link linkend="v4l2-input">v4l2_input</link> { | |||
744 | __u32 tuner; /* Associated tuner */ | 837 | __u32 tuner; /* Associated tuner */ |
745 | v4l2_std_id std; | 838 | v4l2_std_id std; |
746 | __u32 status; | 839 | __u32 status; |
747 | __u32 reserved[4]; | 840 | __u32 capabilities; |
841 | __u32 reserved[3]; | ||
748 | }; | 842 | }; |
749 | 843 | ||
750 | /* Values for the 'type' field */ | 844 | /* Values for the 'type' field */ |
@@ -775,6 +869,11 @@ struct <link linkend="v4l2-input">v4l2_input</link> { | |||
775 | #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ | 869 | #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ |
776 | #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ | 870 | #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ |
777 | 871 | ||
872 | /* capabilities flags */ | ||
873 | #define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ | ||
874 | #define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ | ||
875 | #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ | ||
876 | |||
778 | /* | 877 | /* |
779 | * V I D E O O U T P U T S | 878 | * V I D E O O U T P U T S |
780 | */ | 879 | */ |
@@ -785,13 +884,19 @@ struct <link linkend="v4l2-output">v4l2_output</link> { | |||
785 | __u32 audioset; /* Associated audios (bitfield) */ | 884 | __u32 audioset; /* Associated audios (bitfield) */ |
786 | __u32 modulator; /* Associated modulator */ | 885 | __u32 modulator; /* Associated modulator */ |
787 | v4l2_std_id std; | 886 | v4l2_std_id std; |
788 | __u32 reserved[4]; | 887 | __u32 capabilities; |
888 | __u32 reserved[3]; | ||
789 | }; | 889 | }; |
790 | /* Values for the 'type' field */ | 890 | /* Values for the 'type' field */ |
791 | #define V4L2_OUTPUT_TYPE_MODULATOR 1 | 891 | #define V4L2_OUTPUT_TYPE_MODULATOR 1 |
792 | #define V4L2_OUTPUT_TYPE_ANALOG 2 | 892 | #define V4L2_OUTPUT_TYPE_ANALOG 2 |
793 | #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 | 893 | #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 |
794 | 894 | ||
895 | /* capabilities flags */ | ||
896 | #define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ | ||
897 | #define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ | ||
898 | #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ | ||
899 | |||
795 | /* | 900 | /* |
796 | * C O N T R O L S | 901 | * C O N T R O L S |
797 | */ | 902 | */ |
@@ -1626,6 +1731,13 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> { | |||
1626 | #endif | 1731 | #endif |
1627 | 1732 | ||
1628 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link>) | 1733 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link>) |
1734 | #define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link>) | ||
1735 | #define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>) | ||
1736 | #define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>) | ||
1737 | #define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>) | ||
1738 | #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>) | ||
1739 | #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>) | ||
1740 | |||
1629 | /* Reminder: when adding new ioctls please add support for them to | 1741 | /* Reminder: when adding new ioctls please add support for them to |
1630 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ | 1742 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ |
1631 | 1743 | ||
diff --git a/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml new file mode 100644 index 000000000000..1d31427edd1b --- /dev/null +++ b/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml | |||
@@ -0,0 +1,238 @@ | |||
1 | <refentry id="vidioc-enum-dv-presets"> | ||
2 | <refmeta> | ||
3 | <refentrytitle>ioctl VIDIOC_ENUM_DV_PRESETS</refentrytitle> | ||
4 | &manvol; | ||
5 | </refmeta> | ||
6 | |||
7 | <refnamediv> | ||
8 | <refname>VIDIOC_ENUM_DV_PRESETS</refname> | ||
9 | <refpurpose>Enumerate supported Digital Video presets</refpurpose> | ||
10 | </refnamediv> | ||
11 | |||
12 | <refsynopsisdiv> | ||
13 | <funcsynopsis> | ||
14 | <funcprototype> | ||
15 | <funcdef>int <function>ioctl</function></funcdef> | ||
16 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
17 | <paramdef>int <parameter>request</parameter></paramdef> | ||
18 | <paramdef>struct v4l2_dv_enum_preset *<parameter>argp</parameter></paramdef> | ||
19 | </funcprototype> | ||
20 | </funcsynopsis> | ||
21 | </refsynopsisdiv> | ||
22 | |||
23 | <refsect1> | ||
24 | <title>Arguments</title> | ||
25 | |||
26 | <variablelist> | ||
27 | <varlistentry> | ||
28 | <term><parameter>fd</parameter></term> | ||
29 | <listitem> | ||
30 | <para>&fd;</para> | ||
31 | </listitem> | ||
32 | </varlistentry> | ||
33 | <varlistentry> | ||
34 | <term><parameter>request</parameter></term> | ||
35 | <listitem> | ||
36 | <para>VIDIOC_ENUM_DV_PRESETS</para> | ||
37 | </listitem> | ||
38 | </varlistentry> | ||
39 | <varlistentry> | ||
40 | <term><parameter>argp</parameter></term> | ||
41 | <listitem> | ||
42 | <para></para> | ||
43 | </listitem> | ||
44 | </varlistentry> | ||
45 | </variablelist> | ||
46 | </refsect1> | ||
47 | |||
48 | <refsect1> | ||
49 | <title>Description</title> | ||
50 | |||
51 | <para>To query the attributes of a DV preset, applications initialize the | ||
52 | <structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset; | ||
53 | and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this | ||
54 | structure. Drivers fill the rest of the structure or return an | ||
55 | &EINVAL; when the index is out of bounds. To enumerate all DV Presets supported, | ||
56 | applications shall begin at index zero, incrementing by one until the | ||
57 | driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a | ||
58 | different set of DV presets after switching the video input or | ||
59 | output.</para> | ||
60 | |||
61 | <table pgwide="1" frame="none" id="v4l2-dv-enum-preset"> | ||
62 | <title>struct <structname>v4l2_dv_enum_presets</structname></title> | ||
63 | <tgroup cols="3"> | ||
64 | &cs-str; | ||
65 | <tbody valign="top"> | ||
66 | <row> | ||
67 | <entry>__u32</entry> | ||
68 | <entry><structfield>index</structfield></entry> | ||
69 | <entry>Number of the DV preset, set by the | ||
70 | application.</entry> | ||
71 | </row> | ||
72 | <row> | ||
73 | <entry>__u32</entry> | ||
74 | <entry><structfield>preset</structfield></entry> | ||
75 | <entry>This field identifies one of the DV preset values listed in <xref linkend="v4l2-dv-presets-vals"/>.</entry> | ||
76 | </row> | ||
77 | <row> | ||
78 | <entry>__u8</entry> | ||
79 | <entry><structfield>name</structfield>[24]</entry> | ||
80 | <entry>Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is | ||
81 | intended for the user.</entry> | ||
82 | </row> | ||
83 | <row> | ||
84 | <entry>__u32</entry> | ||
85 | <entry><structfield>width</structfield></entry> | ||
86 | <entry>Width of the active video in pixels for the DV preset.</entry> | ||
87 | </row> | ||
88 | <row> | ||
89 | <entry>__u32</entry> | ||
90 | <entry><structfield>height</structfield></entry> | ||
91 | <entry>Height of the active video in lines for the DV preset.</entry> | ||
92 | </row> | ||
93 | <row> | ||
94 | <entry>__u32</entry> | ||
95 | <entry><structfield>reserved</structfield>[4]</entry> | ||
96 | <entry>Reserved for future extensions. Drivers must set the array to zero.</entry> | ||
97 | </row> | ||
98 | </tbody> | ||
99 | </tgroup> | ||
100 | </table> | ||
101 | |||
102 | <table pgwide="1" frame="none" id="v4l2-dv-presets-vals"> | ||
103 | <title>struct <structname>DV Presets</structname></title> | ||
104 | <tgroup cols="3"> | ||
105 | &cs-str; | ||
106 | <tbody valign="top"> | ||
107 | <row> | ||
108 | <entry>Preset</entry> | ||
109 | <entry>Preset value</entry> | ||
110 | <entry>Description</entry> | ||
111 | </row> | ||
112 | <row> | ||
113 | <entry></entry> | ||
114 | <entry></entry> | ||
115 | <entry></entry> | ||
116 | </row> | ||
117 | <row> | ||
118 | <entry>V4L2_DV_INVALID</entry> | ||
119 | <entry>0</entry> | ||
120 | <entry>Invalid preset value.</entry> | ||
121 | </row> | ||
122 | <row> | ||
123 | <entry>V4L2_DV_480P59_94</entry> | ||
124 | <entry>1</entry> | ||
125 | <entry>720x480 progressive video at 59.94 fps as per BT.1362.</entry> | ||
126 | </row> | ||
127 | <row> | ||
128 | <entry>V4L2_DV_576P50</entry> | ||
129 | <entry>2</entry> | ||
130 | <entry>720x576 progressive video at 50 fps as per BT.1362.</entry> | ||
131 | </row> | ||
132 | <row> | ||
133 | <entry>V4L2_DV_720P24</entry> | ||
134 | <entry>3</entry> | ||
135 | <entry>1280x720 progressive video at 24 fps as per SMPTE 296M.</entry> | ||
136 | </row> | ||
137 | <row> | ||
138 | <entry>V4L2_DV_720P25</entry> | ||
139 | <entry>4</entry> | ||
140 | <entry>1280x720 progressive video at 25 fps as per SMPTE 296M.</entry> | ||
141 | </row> | ||
142 | <row> | ||
143 | <entry>V4L2_DV_720P30</entry> | ||
144 | <entry>5</entry> | ||
145 | <entry>1280x720 progressive video at 30 fps as per SMPTE 296M.</entry> | ||
146 | </row> | ||
147 | <row> | ||
148 | <entry>V4L2_DV_720P50</entry> | ||
149 | <entry>6</entry> | ||
150 | <entry>1280x720 progressive video at 50 fps as per SMPTE 296M.</entry> | ||
151 | </row> | ||
152 | <row> | ||
153 | <entry>V4L2_DV_720P59_94</entry> | ||
154 | <entry>7</entry> | ||
155 | <entry>1280x720 progressive video at 59.94 fps as per SMPTE 274M.</entry> | ||
156 | </row> | ||
157 | <row> | ||
158 | <entry>V4L2_DV_720P60</entry> | ||
159 | <entry>8</entry> | ||
160 | <entry>1280x720 progressive video at 60 fps as per SMPTE 274M/296M.</entry> | ||
161 | </row> | ||
162 | <row> | ||
163 | <entry>V4L2_DV_1080I29_97</entry> | ||
164 | <entry>9</entry> | ||
165 | <entry>1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.</entry> | ||
166 | </row> | ||
167 | <row> | ||
168 | <entry>V4L2_DV_1080I30</entry> | ||
169 | <entry>10</entry> | ||
170 | <entry>1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.</entry> | ||
171 | </row> | ||
172 | <row> | ||
173 | <entry>V4L2_DV_1080I25</entry> | ||
174 | <entry>11</entry> | ||
175 | <entry>1920x1080 interlaced video at 25 fps as per BT.1120.</entry> | ||
176 | </row> | ||
177 | <row> | ||
178 | <entry>V4L2_DV_1080I50</entry> | ||
179 | <entry>12</entry> | ||
180 | <entry>1920x1080 interlaced video at 50 fps as per SMPTE 296M.</entry> | ||
181 | </row> | ||
182 | <row> | ||
183 | <entry>V4L2_DV_1080I60</entry> | ||
184 | <entry>13</entry> | ||
185 | <entry>1920x1080 interlaced video at 60 fps as per SMPTE 296M.</entry> | ||
186 | </row> | ||
187 | <row> | ||
188 | <entry>V4L2_DV_1080P24</entry> | ||
189 | <entry>14</entry> | ||
190 | <entry>1920x1080 progressive video at 24 fps as per SMPTE 296M.</entry> | ||
191 | </row> | ||
192 | <row> | ||
193 | <entry>V4L2_DV_1080P25</entry> | ||
194 | <entry>15</entry> | ||
195 | <entry>1920x1080 progressive video at 25 fps as per SMPTE 296M.</entry> | ||
196 | </row> | ||
197 | <row> | ||
198 | <entry>V4L2_DV_1080P30</entry> | ||
199 | <entry>16</entry> | ||
200 | <entry>1920x1080 progressive video at 30 fps as per SMPTE 296M.</entry> | ||
201 | </row> | ||
202 | <row> | ||
203 | <entry>V4L2_DV_1080P50</entry> | ||
204 | <entry>17</entry> | ||
205 | <entry>1920x1080 progressive video at 50 fps as per BT.1120.</entry> | ||
206 | </row> | ||
207 | <row> | ||
208 | <entry>V4L2_DV_1080P60</entry> | ||
209 | <entry>18</entry> | ||
210 | <entry>1920x1080 progressive video at 60 fps as per BT.1120.</entry> | ||
211 | </row> | ||
212 | </tbody> | ||
213 | </tgroup> | ||
214 | </table> | ||
215 | </refsect1> | ||
216 | |||
217 | <refsect1> | ||
218 | &return-value; | ||
219 | |||
220 | <variablelist> | ||
221 | <varlistentry> | ||
222 | <term><errorcode>EINVAL</errorcode></term> | ||
223 | <listitem> | ||
224 | <para>The &v4l2-dv-enum-preset; <structfield>index</structfield> | ||
225 | is out of bounds.</para> | ||
226 | </listitem> | ||
227 | </varlistentry> | ||
228 | </variablelist> | ||
229 | </refsect1> | ||
230 | </refentry> | ||
231 | |||
232 | <!-- | ||
233 | Local Variables: | ||
234 | mode: sgml | ||
235 | sgml-parent-document: "v4l2.sgml" | ||
236 | indent-tabs-mode: nil | ||
237 | End: | ||
238 | --> | ||
diff --git a/Documentation/DocBook/v4l/vidioc-enuminput.xml b/Documentation/DocBook/v4l/vidioc-enuminput.xml index 414856b82473..71b868e2fb8f 100644 --- a/Documentation/DocBook/v4l/vidioc-enuminput.xml +++ b/Documentation/DocBook/v4l/vidioc-enuminput.xml | |||
@@ -124,7 +124,13 @@ current input.</entry> | |||
124 | </row> | 124 | </row> |
125 | <row> | 125 | <row> |
126 | <entry>__u32</entry> | 126 | <entry>__u32</entry> |
127 | <entry><structfield>reserved</structfield>[4]</entry> | 127 | <entry><structfield>capabilities</structfield></entry> |
128 | <entry>This field provides capabilities for the | ||
129 | input. See <xref linkend="input-capabilities" /> for flags.</entry> | ||
130 | </row> | ||
131 | <row> | ||
132 | <entry>__u32</entry> | ||
133 | <entry><structfield>reserved</structfield>[3]</entry> | ||
128 | <entry>Reserved for future extensions. Drivers must set | 134 | <entry>Reserved for future extensions. Drivers must set |
129 | the array to zero.</entry> | 135 | the array to zero.</entry> |
130 | </row> | 136 | </row> |
@@ -261,6 +267,34 @@ flag is set Macrovision has been detected.</entry> | |||
261 | </tbody> | 267 | </tbody> |
262 | </tgroup> | 268 | </tgroup> |
263 | </table> | 269 | </table> |
270 | |||
271 | <!-- Capability flags based on video timings RFC by Muralidharan | ||
272 | Karicheri, titled RFC (v1.2): V4L - Support for video timings at the | ||
273 | input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. | ||
274 | --> | ||
275 | <table frame="none" pgwide="1" id="input-capabilities"> | ||
276 | <title>Input capabilities</title> | ||
277 | <tgroup cols="3"> | ||
278 | &cs-def; | ||
279 | <tbody valign="top"> | ||
280 | <row> | ||
281 | <entry><constant>V4L2_IN_CAP_PRESETS</constant></entry> | ||
282 | <entry>0x00000001</entry> | ||
283 | <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry> | ||
284 | </row> | ||
285 | <row> | ||
286 | <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry> | ||
287 | <entry>0x00000002</entry> | ||
288 | <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry> | ||
289 | </row> | ||
290 | <row> | ||
291 | <entry><constant>V4L2_IN_CAP_STD</constant></entry> | ||
292 | <entry>0x00000004</entry> | ||
293 | <entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry> | ||
294 | </row> | ||
295 | </tbody> | ||
296 | </tgroup> | ||
297 | </table> | ||
264 | </refsect1> | 298 | </refsect1> |
265 | 299 | ||
266 | <refsect1> | 300 | <refsect1> |
diff --git a/Documentation/DocBook/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/v4l/vidioc-enumoutput.xml index e8d16dcd50cf..a281d26a195f 100644 --- a/Documentation/DocBook/v4l/vidioc-enumoutput.xml +++ b/Documentation/DocBook/v4l/vidioc-enumoutput.xml | |||
@@ -114,7 +114,13 @@ details on video standards and how to switch see <xref | |||
114 | </row> | 114 | </row> |
115 | <row> | 115 | <row> |
116 | <entry>__u32</entry> | 116 | <entry>__u32</entry> |
117 | <entry><structfield>reserved</structfield>[4]</entry> | 117 | <entry><structfield>capabilities</structfield></entry> |
118 | <entry>This field provides capabilities for the | ||
119 | output. See <xref linkend="output-capabilities" /> for flags.</entry> | ||
120 | </row> | ||
121 | <row> | ||
122 | <entry>__u32</entry> | ||
123 | <entry><structfield>reserved</structfield>[3]</entry> | ||
118 | <entry>Reserved for future extensions. Drivers must set | 124 | <entry>Reserved for future extensions. Drivers must set |
119 | the array to zero.</entry> | 125 | the array to zero.</entry> |
120 | </row> | 126 | </row> |
@@ -147,6 +153,34 @@ CVBS, S-Video, RGB.</entry> | |||
147 | </tgroup> | 153 | </tgroup> |
148 | </table> | 154 | </table> |
149 | 155 | ||
156 | <!-- Capabilities flags based on video timings RFC by Muralidharan | ||
157 | Karicheri, titled RFC (v1.2): V4L - Support for video timings at the | ||
158 | input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. | ||
159 | --> | ||
160 | <table frame="none" pgwide="1" id="output-capabilities"> | ||
161 | <title>Output capabilities</title> | ||
162 | <tgroup cols="3"> | ||
163 | &cs-def; | ||
164 | <tbody valign="top"> | ||
165 | <row> | ||
166 | <entry><constant>V4L2_OUT_CAP_PRESETS</constant></entry> | ||
167 | <entry>0x00000001</entry> | ||
168 | <entry>This output supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry> | ||
169 | </row> | ||
170 | <row> | ||
171 | <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry> | ||
172 | <entry>0x00000002</entry> | ||
173 | <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry> | ||
174 | </row> | ||
175 | <row> | ||
176 | <entry><constant>V4L2_OUT_CAP_STD</constant></entry> | ||
177 | <entry>0x00000004</entry> | ||
178 | <entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry> | ||
179 | </row> | ||
180 | </tbody> | ||
181 | </tgroup> | ||
182 | </table> | ||
183 | |||
150 | </refsect1> | 184 | </refsect1> |
151 | <refsect1> | 185 | <refsect1> |
152 | &return-value; | 186 | &return-value; |
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml new file mode 100644 index 000000000000..3c6784e132f3 --- /dev/null +++ b/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml | |||
@@ -0,0 +1,111 @@ | |||
1 | <refentry id="vidioc-g-dv-preset"> | ||
2 | <refmeta> | ||
3 | <refentrytitle>ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</refentrytitle> | ||
4 | &manvol; | ||
5 | </refmeta> | ||
6 | |||
7 | <refnamediv> | ||
8 | <refname>VIDIOC_G_DV_PRESET</refname> | ||
9 | <refname>VIDIOC_S_DV_PRESET</refname> | ||
10 | <refpurpose>Query or select the DV preset of the current input or output</refpurpose> | ||
11 | </refnamediv> | ||
12 | |||
13 | <refsynopsisdiv> | ||
14 | <funcsynopsis> | ||
15 | <funcprototype> | ||
16 | <funcdef>int <function>ioctl</function></funcdef> | ||
17 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
18 | <paramdef>int <parameter>request</parameter></paramdef> | ||
19 | <paramdef>&v4l2-dv-preset; | ||
20 | *<parameter>argp</parameter></paramdef> | ||
21 | </funcprototype> | ||
22 | </funcsynopsis> | ||
23 | </refsynopsisdiv> | ||
24 | |||
25 | <refsect1> | ||
26 | <title>Arguments</title> | ||
27 | |||
28 | <variablelist> | ||
29 | <varlistentry> | ||
30 | <term><parameter>fd</parameter></term> | ||
31 | <listitem> | ||
32 | <para>&fd;</para> | ||
33 | </listitem> | ||
34 | </varlistentry> | ||
35 | <varlistentry> | ||
36 | <term><parameter>request</parameter></term> | ||
37 | <listitem> | ||
38 | <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</para> | ||
39 | </listitem> | ||
40 | </varlistentry> | ||
41 | <varlistentry> | ||
42 | <term><parameter>argp</parameter></term> | ||
43 | <listitem> | ||
44 | <para></para> | ||
45 | </listitem> | ||
46 | </varlistentry> | ||
47 | </variablelist> | ||
48 | </refsect1> | ||
49 | |||
50 | <refsect1> | ||
51 | <title>Description</title> | ||
52 | <para>To query and select the current DV preset, applications | ||
53 | use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant> | ||
54 | ioctls which take a pointer to a &v4l2-dv-preset; type as argument. | ||
55 | Applications must zero the reserved array in &v4l2-dv-preset;. | ||
56 | <constant>VIDIOC_G_DV_PRESET</constant> returns a dv preset in the field | ||
57 | <structfield>preset</structfield> of &v4l2-dv-preset;.</para> | ||
58 | |||
59 | <para><constant>VIDIOC_S_DV_PRESET</constant> accepts a pointer to a &v4l2-dv-preset; | ||
60 | that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;. | ||
61 | If the preset is not supported, it returns an &EINVAL; </para> | ||
62 | </refsect1> | ||
63 | |||
64 | <refsect1> | ||
65 | &return-value; | ||
66 | |||
67 | <variablelist> | ||
68 | <varlistentry> | ||
69 | <term><errorcode>EINVAL</errorcode></term> | ||
70 | <listitem> | ||
71 | <para>This ioctl is not supported, or the | ||
72 | <constant>VIDIOC_S_DV_PRESET</constant>,<constant>VIDIOC_S_DV_PRESET</constant> parameter was unsuitable.</para> | ||
73 | </listitem> | ||
74 | </varlistentry> | ||
75 | <varlistentry> | ||
76 | <term><errorcode>EBUSY</errorcode></term> | ||
77 | <listitem> | ||
78 | <para>The device is busy and therefore can not change the preset.</para> | ||
79 | </listitem> | ||
80 | </varlistentry> | ||
81 | </variablelist> | ||
82 | |||
83 | <table pgwide="1" frame="none" id="v4l2-dv-preset"> | ||
84 | <title>struct <structname>v4l2_dv_preset</structname></title> | ||
85 | <tgroup cols="3"> | ||
86 | &cs-str; | ||
87 | <tbody valign="top"> | ||
88 | <row> | ||
89 | <entry>__u32</entry> | ||
90 | <entry><structfield>preset</structfield></entry> | ||
91 | <entry>Preset value to represent the digital video timings</entry> | ||
92 | </row> | ||
93 | <row> | ||
94 | <entry>__u32</entry> | ||
95 | <entry><structfield>reserved[4]</structfield></entry> | ||
96 | <entry>Reserved fields for future use</entry> | ||
97 | </row> | ||
98 | </tbody> | ||
99 | </tgroup> | ||
100 | </table> | ||
101 | |||
102 | </refsect1> | ||
103 | </refentry> | ||
104 | |||
105 | <!-- | ||
106 | Local Variables: | ||
107 | mode: sgml | ||
108 | sgml-parent-document: "v4l2.sgml" | ||
109 | indent-tabs-mode: nil | ||
110 | End: | ||
111 | --> | ||
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml new file mode 100644 index 000000000000..ecc19576bb8f --- /dev/null +++ b/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml | |||
@@ -0,0 +1,224 @@ | |||
1 | <refentry id="vidioc-g-dv-timings"> | ||
2 | <refmeta> | ||
3 | <refentrytitle>ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</refentrytitle> | ||
4 | &manvol; | ||
5 | </refmeta> | ||
6 | |||
7 | <refnamediv> | ||
8 | <refname>VIDIOC_G_DV_TIMINGS</refname> | ||
9 | <refname>VIDIOC_S_DV_TIMINGS</refname> | ||
10 | <refpurpose>Get or set custom DV timings for input or output</refpurpose> | ||
11 | </refnamediv> | ||
12 | |||
13 | <refsynopsisdiv> | ||
14 | <funcsynopsis> | ||
15 | <funcprototype> | ||
16 | <funcdef>int <function>ioctl</function></funcdef> | ||
17 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
18 | <paramdef>int <parameter>request</parameter></paramdef> | ||
19 | <paramdef>&v4l2-dv-timings; | ||
20 | *<parameter>argp</parameter></paramdef> | ||
21 | </funcprototype> | ||
22 | </funcsynopsis> | ||
23 | </refsynopsisdiv> | ||
24 | |||
25 | <refsect1> | ||
26 | <title>Arguments</title> | ||
27 | |||
28 | <variablelist> | ||
29 | <varlistentry> | ||
30 | <term><parameter>fd</parameter></term> | ||
31 | <listitem> | ||
32 | <para>&fd;</para> | ||
33 | </listitem> | ||
34 | </varlistentry> | ||
35 | <varlistentry> | ||
36 | <term><parameter>request</parameter></term> | ||
37 | <listitem> | ||
38 | <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</para> | ||
39 | </listitem> | ||
40 | </varlistentry> | ||
41 | <varlistentry> | ||
42 | <term><parameter>argp</parameter></term> | ||
43 | <listitem> | ||
44 | <para></para> | ||
45 | </listitem> | ||
46 | </varlistentry> | ||
47 | </variablelist> | ||
48 | </refsect1> | ||
49 | |||
50 | <refsect1> | ||
51 | <title>Description</title> | ||
52 | <para>To set custom DV timings for the input or output, applications use the | ||
53 | <constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings, | ||
54 | applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing | ||
55 | information is filled in using the structure &v4l2-dv-timings;. These ioctls take | ||
56 | a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported | ||
57 | or the timing values are not correct, the driver returns &EINVAL;.</para> | ||
58 | </refsect1> | ||
59 | |||
60 | <refsect1> | ||
61 | &return-value; | ||
62 | |||
63 | <variablelist> | ||
64 | <varlistentry> | ||
65 | <term><errorcode>EINVAL</errorcode></term> | ||
66 | <listitem> | ||
67 | <para>This ioctl is not supported, or the | ||
68 | <constant>VIDIOC_S_DV_TIMINGS</constant> parameter was unsuitable.</para> | ||
69 | </listitem> | ||
70 | </varlistentry> | ||
71 | <varlistentry> | ||
72 | <term><errorcode>EBUSY</errorcode></term> | ||
73 | <listitem> | ||
74 | <para>The device is busy and therefore can not change the timings.</para> | ||
75 | </listitem> | ||
76 | </varlistentry> | ||
77 | </variablelist> | ||
78 | |||
79 | <table pgwide="1" frame="none" id="v4l2-bt-timings"> | ||
80 | <title>struct <structname>v4l2_bt_timings</structname></title> | ||
81 | <tgroup cols="3"> | ||
82 | &cs-str; | ||
83 | <tbody valign="top"> | ||
84 | <row> | ||
85 | <entry>__u32</entry> | ||
86 | <entry><structfield>width</structfield></entry> | ||
87 | <entry>Width of the active video in pixels</entry> | ||
88 | </row> | ||
89 | <row> | ||
90 | <entry>__u32</entry> | ||
91 | <entry><structfield>height</structfield></entry> | ||
92 | <entry>Height of the active video in lines</entry> | ||
93 | </row> | ||
94 | <row> | ||
95 | <entry>__u32</entry> | ||
96 | <entry><structfield>interlaced</structfield></entry> | ||
97 | <entry>Progressive (0) or interlaced (1)</entry> | ||
98 | </row> | ||
99 | <row> | ||
100 | <entry>__u32</entry> | ||
101 | <entry><structfield>polarities</structfield></entry> | ||
102 | <entry>This is a bit mask that defines polarities of sync signals. | ||
103 | 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 | ||
104 | (1) it is positive polarity and if is cleared (0), it is negative polarity.</entry> | ||
105 | </row> | ||
106 | <row> | ||
107 | <entry>__u64</entry> | ||
108 | <entry><structfield>pixelclock</structfield></entry> | ||
109 | <entry>Pixel clock in Hz. Ex. 74.25MHz->74250000</entry> | ||
110 | </row> | ||
111 | <row> | ||
112 | <entry>__u32</entry> | ||
113 | <entry><structfield>hfrontporch</structfield></entry> | ||
114 | <entry>Horizontal front porch in pixels</entry> | ||
115 | </row> | ||
116 | <row> | ||
117 | <entry>__u32</entry> | ||
118 | <entry><structfield>hsync</structfield></entry> | ||
119 | <entry>Horizontal sync length in pixels</entry> | ||
120 | </row> | ||
121 | <row> | ||
122 | <entry>__u32</entry> | ||
123 | <entry><structfield>hbackporch</structfield></entry> | ||
124 | <entry>Horizontal back porch in pixels</entry> | ||
125 | </row> | ||
126 | <row> | ||
127 | <entry>__u32</entry> | ||
128 | <entry><structfield>vfrontporch</structfield></entry> | ||
129 | <entry>Vertical front porch in lines</entry> | ||
130 | </row> | ||
131 | <row> | ||
132 | <entry>__u32</entry> | ||
133 | <entry><structfield>vsync</structfield></entry> | ||
134 | <entry>Vertical sync length in lines</entry> | ||
135 | </row> | ||
136 | <row> | ||
137 | <entry>__u32</entry> | ||
138 | <entry><structfield>vbackporch</structfield></entry> | ||
139 | <entry>Vertical back porch in lines</entry> | ||
140 | </row> | ||
141 | <row> | ||
142 | <entry>__u32</entry> | ||
143 | <entry><structfield>il_vfrontporch</structfield></entry> | ||
144 | <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry> | ||
145 | </row> | ||
146 | <row> | ||
147 | <entry>__u32</entry> | ||
148 | <entry><structfield>il_vsync</structfield></entry> | ||
149 | <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry> | ||
150 | </row> | ||
151 | <row> | ||
152 | <entry>__u32</entry> | ||
153 | <entry><structfield>il_vbackporch</structfield></entry> | ||
154 | <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry> | ||
155 | </row> | ||
156 | </tbody> | ||
157 | </tgroup> | ||
158 | </table> | ||
159 | |||
160 | <table pgwide="1" frame="none" id="v4l2-dv-timings"> | ||
161 | <title>struct <structname>v4l2_dv_timings</structname></title> | ||
162 | <tgroup cols="4"> | ||
163 | &cs-str; | ||
164 | <tbody valign="top"> | ||
165 | <row> | ||
166 | <entry>__u32</entry> | ||
167 | <entry><structfield>type</structfield></entry> | ||
168 | <entry></entry> | ||
169 | <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry> | ||
170 | </row> | ||
171 | <row> | ||
172 | <entry>union</entry> | ||
173 | <entry><structfield></structfield></entry> | ||
174 | <entry></entry> | ||
175 | </row> | ||
176 | <row> | ||
177 | <entry></entry> | ||
178 | <entry>&v4l2-bt-timings;</entry> | ||
179 | <entry><structfield>bt</structfield></entry> | ||
180 | <entry>Timings defined by BT.656/1120 specifications</entry> | ||
181 | </row> | ||
182 | <row> | ||
183 | <entry></entry> | ||
184 | <entry>__u32</entry> | ||
185 | <entry><structfield>reserved</structfield>[32]</entry> | ||
186 | <entry></entry> | ||
187 | </row> | ||
188 | </tbody> | ||
189 | </tgroup> | ||
190 | </table> | ||
191 | |||
192 | <table pgwide="1" frame="none" id="dv-timing-types"> | ||
193 | <title>DV Timing types</title> | ||
194 | <tgroup cols="3"> | ||
195 | &cs-str; | ||
196 | <tbody valign="top"> | ||
197 | <row> | ||
198 | <entry>Timing type</entry> | ||
199 | <entry>value</entry> | ||
200 | <entry>Description</entry> | ||
201 | </row> | ||
202 | <row> | ||
203 | <entry></entry> | ||
204 | <entry></entry> | ||
205 | <entry></entry> | ||
206 | </row> | ||
207 | <row> | ||
208 | <entry>V4L2_DV_BT_656_1120</entry> | ||
209 | <entry>0</entry> | ||
210 | <entry>BT.656/1120 timings</entry> | ||
211 | </row> | ||
212 | </tbody> | ||
213 | </tgroup> | ||
214 | </table> | ||
215 | </refsect1> | ||
216 | </refentry> | ||
217 | |||
218 | <!-- | ||
219 | Local Variables: | ||
220 | mode: sgml | ||
221 | sgml-parent-document: "v4l2.sgml" | ||
222 | indent-tabs-mode: nil | ||
223 | End: | ||
224 | --> | ||
diff --git a/Documentation/DocBook/v4l/vidioc-g-std.xml b/Documentation/DocBook/v4l/vidioc-g-std.xml index b6f5d267e856..912f8513e5da 100644 --- a/Documentation/DocBook/v4l/vidioc-g-std.xml +++ b/Documentation/DocBook/v4l/vidioc-g-std.xml | |||
@@ -86,6 +86,12 @@ standards.</para> | |||
86 | <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para> | 86 | <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para> |
87 | </listitem> | 87 | </listitem> |
88 | </varlistentry> | 88 | </varlistentry> |
89 | <varlistentry> | ||
90 | <term><errorcode>EBUSY</errorcode></term> | ||
91 | <listitem> | ||
92 | <para>The device is busy and therefore can not change the standard</para> | ||
93 | </listitem> | ||
94 | </varlistentry> | ||
89 | </variablelist> | 95 | </variablelist> |
90 | </refsect1> | 96 | </refsect1> |
91 | </refentry> | 97 | </refentry> |
diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml new file mode 100644 index 000000000000..87e4f0f6151c --- /dev/null +++ b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml | |||
@@ -0,0 +1,85 @@ | |||
1 | <refentry id="vidioc-query-dv-preset"> | ||
2 | <refmeta> | ||
3 | <refentrytitle>ioctl VIDIOC_QUERY_DV_PRESET</refentrytitle> | ||
4 | &manvol; | ||
5 | </refmeta> | ||
6 | |||
7 | <refnamediv> | ||
8 | <refname>VIDIOC_QUERY_DV_PRESET</refname> | ||
9 | <refpurpose>Sense the DV preset received by the current | ||
10 | input</refpurpose> | ||
11 | </refnamediv> | ||
12 | |||
13 | <refsynopsisdiv> | ||
14 | <funcsynopsis> | ||
15 | <funcprototype> | ||
16 | <funcdef>int <function>ioctl</function></funcdef> | ||
17 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
18 | <paramdef>int <parameter>request</parameter></paramdef> | ||
19 | <paramdef>&v4l2-dv-preset; *<parameter>argp</parameter></paramdef> | ||
20 | </funcprototype> | ||
21 | </funcsynopsis> | ||
22 | </refsynopsisdiv> | ||
23 | |||
24 | <refsect1> | ||
25 | <title>Arguments</title> | ||
26 | |||
27 | <variablelist> | ||
28 | <varlistentry> | ||
29 | <term><parameter>fd</parameter></term> | ||
30 | <listitem> | ||
31 | <para>&fd;</para> | ||
32 | </listitem> | ||
33 | </varlistentry> | ||
34 | <varlistentry> | ||
35 | <term><parameter>request</parameter></term> | ||
36 | <listitem> | ||
37 | <para>VIDIOC_QUERY_DV_PRESET</para> | ||
38 | </listitem> | ||
39 | </varlistentry> | ||
40 | <varlistentry> | ||
41 | <term><parameter>argp</parameter></term> | ||
42 | <listitem> | ||
43 | <para></para> | ||
44 | </listitem> | ||
45 | </varlistentry> | ||
46 | </variablelist> | ||
47 | </refsect1> | ||
48 | |||
49 | <refsect1> | ||
50 | <title>Description</title> | ||
51 | |||
52 | <para>The hardware may be able to detect the current DV preset | ||
53 | automatically, similar to sensing the video standard. To do so, applications | ||
54 | call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a | ||
55 | &v4l2-dv-preset; type. Once the hardware detects a preset, that preset is | ||
56 | returned in the preset field of &v4l2-dv-preset;. When detection is not | ||
57 | possible or fails, the value V4L2_DV_INVALID is returned.</para> | ||
58 | </refsect1> | ||
59 | |||
60 | <refsect1> | ||
61 | &return-value; | ||
62 | <variablelist> | ||
63 | <varlistentry> | ||
64 | <term><errorcode>EINVAL</errorcode></term> | ||
65 | <listitem> | ||
66 | <para>This ioctl is not supported.</para> | ||
67 | </listitem> | ||
68 | </varlistentry> | ||
69 | <varlistentry> | ||
70 | <term><errorcode>EBUSY</errorcode></term> | ||
71 | <listitem> | ||
72 | <para>The device is busy and therefore can not sense the preset</para> | ||
73 | </listitem> | ||
74 | </varlistentry> | ||
75 | </variablelist> | ||
76 | </refsect1> | ||
77 | </refentry> | ||
78 | |||
79 | <!-- | ||
80 | Local Variables: | ||
81 | mode: sgml | ||
82 | sgml-parent-document: "v4l2.sgml" | ||
83 | indent-tabs-mode: nil | ||
84 | End: | ||
85 | --> | ||
diff --git a/Documentation/DocBook/v4l/vidioc-querystd.xml b/Documentation/DocBook/v4l/vidioc-querystd.xml index b5a7ff934486..1a9e60393091 100644 --- a/Documentation/DocBook/v4l/vidioc-querystd.xml +++ b/Documentation/DocBook/v4l/vidioc-querystd.xml | |||
@@ -70,6 +70,12 @@ current video input or output.</para> | |||
70 | <para>This ioctl is not supported.</para> | 70 | <para>This ioctl is not supported.</para> |
71 | </listitem> | 71 | </listitem> |
72 | </varlistentry> | 72 | </varlistentry> |
73 | <varlistentry> | ||
74 | <term><errorcode>EBUSY</errorcode></term> | ||
75 | <listitem> | ||
76 | <para>The device is busy and therefore can not detect the standard</para> | ||
77 | </listitem> | ||
78 | </varlistentry> | ||
73 | </variablelist> | 79 | </variablelist> |
74 | </refsect1> | 80 | </refsect1> |
75 | </refentry> | 81 | </refentry> |
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist index 78a9168ff377..1053a56be3b1 100644 --- a/Documentation/SubmitChecklist +++ b/Documentation/SubmitChecklist | |||
@@ -15,7 +15,7 @@ kernel patches. | |||
15 | 2: Passes allnoconfig, allmodconfig | 15 | 2: Passes allnoconfig, allmodconfig |
16 | 16 | ||
17 | 3: Builds on multiple CPU architectures by using local cross-compile tools | 17 | 3: Builds on multiple CPU architectures by using local cross-compile tools |
18 | or something like PLM at OSDL. | 18 | or some other build farm. |
19 | 19 | ||
20 | 4: ppc64 is a good architecture for cross-compilation checking because it | 20 | 4: ppc64 is a good architecture for cross-compilation checking because it |
21 | tends to use `unsigned long' for 64-bit quantities. | 21 | tends to use `unsigned long' for 64-bit quantities. |
@@ -88,3 +88,6 @@ kernel patches. | |||
88 | 88 | ||
89 | 24: All memory barriers {e.g., barrier(), rmb(), wmb()} need a comment in the | 89 | 24: All memory barriers {e.g., barrier(), rmb(), wmb()} need a comment in the |
90 | source code that explains the logic of what they are doing and why. | 90 | source code that explains the logic of what they are doing and why. |
91 | |||
92 | 25: If any ioctl's are added by the patch, then also update | ||
93 | Documentation/ioctl/ioctl-number.txt. | ||
diff --git a/Documentation/fb/viafb.txt b/Documentation/fb/viafb.txt index 67dbf442b0b6..f3e046a6a987 100644 --- a/Documentation/fb/viafb.txt +++ b/Documentation/fb/viafb.txt | |||
@@ -7,7 +7,7 @@ | |||
7 | VIA UniChrome Family(CLE266, PM800 / CN400 / CN300, | 7 | VIA UniChrome Family(CLE266, PM800 / CN400 / CN300, |
8 | P4M800CE / P4M800Pro / CN700 / VN800, | 8 | P4M800CE / P4M800Pro / CN700 / VN800, |
9 | CX700 / VX700, K8M890, P4M890, | 9 | CX700 / VX700, K8M890, P4M890, |
10 | CN896 / P4M900, VX800) | 10 | CN896 / P4M900, VX800, VX855) |
11 | 11 | ||
12 | [Driver features] | 12 | [Driver features] |
13 | ------------------------ | 13 | ------------------------ |
@@ -154,13 +154,6 @@ | |||
154 | 0 : No Dual Edge Panel (default) | 154 | 0 : No Dual Edge Panel (default) |
155 | 1 : Dual Edge Panel | 155 | 1 : Dual Edge Panel |
156 | 156 | ||
157 | viafb_video_dev: | ||
158 | This option is used to specify video output devices(CRT, DVI, LCD) for | ||
159 | duoview case. | ||
160 | For example: | ||
161 | To output video on DVI, we should use: | ||
162 | modprobe viafb viafb_video_dev=DVI... | ||
163 | |||
164 | viafb_lcd_port: | 157 | viafb_lcd_port: |
165 | This option is used to specify LCD output port, | 158 | This option is used to specify LCD output port, |
166 | available values are "DVP0" "DVP1" "DFP_HIGHLOW" "DFP_HIGH" "DFP_LOW". | 159 | available values are "DVP0" "DVP1" "DFP_HIGHLOW" "DFP_HIGH" "DFP_LOW". |
@@ -181,9 +174,6 @@ Notes: | |||
181 | and bpp, need to call VIAFB specified ioctl interface VIAFB_SET_DEVICE | 174 | and bpp, need to call VIAFB specified ioctl interface VIAFB_SET_DEVICE |
182 | instead of calling common ioctl function FBIOPUT_VSCREENINFO since | 175 | instead of calling common ioctl function FBIOPUT_VSCREENINFO since |
183 | viafb doesn't support multi-head well, or it will cause screen crush. | 176 | viafb doesn't support multi-head well, or it will cause screen crush. |
184 | 4. VX800 2D accelerator hasn't been supported in this driver yet. When | ||
185 | using driver on VX800, the driver will disable the acceleration | ||
186 | function as default. | ||
187 | 177 | ||
188 | 178 | ||
189 | [Configure viafb with "fbset" tool] | 179 | [Configure viafb with "fbset" tool] |
diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index 0d15ebccf5b0..a1e2e0dda907 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt | |||
@@ -248,9 +248,7 @@ code, that is done in the initialization code in the usual way: | |||
248 | { | 248 | { |
249 | struct proc_dir_entry *entry; | 249 | struct proc_dir_entry *entry; |
250 | 250 | ||
251 | entry = create_proc_entry("sequence", 0, NULL); | 251 | proc_create("sequence", 0, NULL, &ct_file_ops); |
252 | if (entry) | ||
253 | entry->proc_fops = &ct_file_ops; | ||
254 | return 0; | 252 | return 0; |
255 | } | 253 | } |
256 | 254 | ||
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index e4e7daed2ba8..1866c27eec69 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt | |||
@@ -531,6 +531,13 @@ and have the following read/write attributes: | |||
531 | This file exists only if the pin can be configured as an | 531 | This file exists only if the pin can be configured as an |
532 | interrupt generating input pin. | 532 | interrupt generating input pin. |
533 | 533 | ||
534 | "active_low" ... reads as either 0 (false) or 1 (true). Write | ||
535 | any nonzero value to invert the value attribute both | ||
536 | for reading and writing. Existing and subsequent | ||
537 | poll(2) support configuration via the edge attribute | ||
538 | for "rising" and "falling" edges will follow this | ||
539 | setting. | ||
540 | |||
534 | GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the | 541 | GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the |
535 | controller implementing GPIOs starting at #42) and have the following | 542 | controller implementing GPIOs starting at #42) and have the following |
536 | read-only attributes: | 543 | read-only attributes: |
@@ -566,6 +573,8 @@ requested using gpio_request(): | |||
566 | int gpio_export_link(struct device *dev, const char *name, | 573 | int gpio_export_link(struct device *dev, const char *name, |
567 | unsigned gpio) | 574 | unsigned gpio) |
568 | 575 | ||
576 | /* change the polarity of a GPIO node in sysfs */ | ||
577 | int gpio_sysfs_set_active_low(unsigned gpio, int value); | ||
569 | 578 | ||
570 | After a kernel driver requests a GPIO, it may only be made available in | 579 | After a kernel driver requests a GPIO, it may only be made available in |
571 | the sysfs interface by gpio_export(). The driver can control whether the | 580 | the sysfs interface by gpio_export(). The driver can control whether the |
@@ -580,3 +589,9 @@ After the GPIO has been exported, gpio_export_link() allows creating | |||
580 | symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can | 589 | symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can |
581 | use this to provide the interface under their own device in sysfs with | 590 | use this to provide the interface under their own device in sysfs with |
582 | a descriptive name. | 591 | a descriptive name. |
592 | |||
593 | Drivers can use gpio_sysfs_set_active_low() to hide GPIO line polarity | ||
594 | differences between boards from user space. This only affects the | ||
595 | sysfs interface. Polarity change can be done both before and after | ||
596 | gpio_export(), and previously enabled poll(2) support for either | ||
597 | rising or falling edge will be reconfigured to follow this setting. | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ab95d3ada5c7..c309515ae959 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -2729,6 +2729,11 @@ and is between 256 and 4096 characters. It is defined in the file | |||
2729 | vmpoff= [KNL,S390] Perform z/VM CP command after power off. | 2729 | vmpoff= [KNL,S390] Perform z/VM CP command after power off. |
2730 | Format: <command> | 2730 | Format: <command> |
2731 | 2731 | ||
2732 | vt.cur_default= [VT] Default cursor shape. | ||
2733 | Format: 0xCCBBAA, where AA, BB, and CC are the same as | ||
2734 | the parameters of the <Esc>[?A;B;Cc escape sequence; | ||
2735 | see VGA-softcursor.txt. Default: 2 = underline. | ||
2736 | |||
2732 | vt.default_blu= [VT] | 2737 | vt.default_blu= [VT] |
2733 | Format: <blue0>,<blue1>,<blue2>,...,<blue15> | 2738 | Format: <blue0>,<blue1>,<blue2>,...,<blue15> |
2734 | Change the default blue palette of the console. | 2739 | Change the default blue palette of the console. |
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 319d9838e87e..1800a62cf135 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt | |||
@@ -12,6 +12,7 @@ m5602 0402:5602 ALi Video Camera Controller | |||
12 | spca501 040a:0002 Kodak DVC-325 | 12 | spca501 040a:0002 Kodak DVC-325 |
13 | spca500 040a:0300 Kodak EZ200 | 13 | spca500 040a:0300 Kodak EZ200 |
14 | zc3xx 041e:041e Creative WebCam Live! | 14 | zc3xx 041e:041e Creative WebCam Live! |
15 | ov519 041e:4003 Video Blaster WebCam Go Plus | ||
15 | spca500 041e:400a Creative PC-CAM 300 | 16 | spca500 041e:400a Creative PC-CAM 300 |
16 | sunplus 041e:400b Creative PC-CAM 600 | 17 | sunplus 041e:400b Creative PC-CAM 600 |
17 | sunplus 041e:4012 PC-Cam350 | 18 | sunplus 041e:4012 PC-Cam350 |
@@ -168,10 +169,14 @@ sunplus 055f:c650 Mustek MDC5500Z | |||
168 | zc3xx 055f:d003 Mustek WCam300A | 169 | zc3xx 055f:d003 Mustek WCam300A |
169 | zc3xx 055f:d004 Mustek WCam300 AN | 170 | zc3xx 055f:d004 Mustek WCam300 AN |
170 | conex 0572:0041 Creative Notebook cx11646 | 171 | conex 0572:0041 Creative Notebook cx11646 |
172 | ov519 05a9:0511 Video Blaster WebCam 3/WebCam Plus, D-Link USB Digital Video Camera | ||
173 | ov519 05a9:0518 Creative WebCam | ||
171 | ov519 05a9:0519 OV519 Microphone | 174 | ov519 05a9:0519 OV519 Microphone |
172 | ov519 05a9:0530 OmniVision | 175 | ov519 05a9:0530 OmniVision |
176 | ov519 05a9:2800 OmniVision SuperCAM | ||
173 | ov519 05a9:4519 Webcam Classic | 177 | ov519 05a9:4519 Webcam Classic |
174 | ov519 05a9:8519 OmniVision | 178 | ov519 05a9:8519 OmniVision |
179 | ov519 05a9:a511 D-Link USB Digital Video Camera | ||
175 | ov519 05a9:a518 D-Link DSB-C310 Webcam | 180 | ov519 05a9:a518 D-Link DSB-C310 Webcam |
176 | sunplus 05da:1018 Digital Dream Enigma 1.3 | 181 | sunplus 05da:1018 Digital Dream Enigma 1.3 |
177 | stk014 05e1:0893 Syntek DV4000 | 182 | stk014 05e1:0893 Syntek DV4000 |
@@ -187,7 +192,7 @@ ov534 06f8:3002 Hercules Blog Webcam | |||
187 | ov534 06f8:3003 Hercules Dualpix HD Weblog | 192 | ov534 06f8:3003 Hercules Dualpix HD Weblog |
188 | sonixj 06f8:3004 Hercules Classic Silver | 193 | sonixj 06f8:3004 Hercules Classic Silver |
189 | sonixj 06f8:3008 Hercules Deluxe Optical Glass | 194 | sonixj 06f8:3008 Hercules Deluxe Optical Glass |
190 | pac7311 06f8:3009 Hercules Classic Link | 195 | pac7302 06f8:3009 Hercules Classic Link |
191 | spca508 0733:0110 ViewQuest VQ110 | 196 | spca508 0733:0110 ViewQuest VQ110 |
192 | spca501 0733:0401 Intel Create and Share | 197 | spca501 0733:0401 Intel Create and Share |
193 | spca501 0733:0402 ViewQuest M318B | 198 | spca501 0733:0402 ViewQuest M318B |
@@ -199,6 +204,7 @@ sunplus 0733:2221 Mercury Digital Pro 3.1p | |||
199 | sunplus 0733:3261 Concord 3045 spca536a | 204 | sunplus 0733:3261 Concord 3045 spca536a |
200 | sunplus 0733:3281 Cyberpix S550V | 205 | sunplus 0733:3281 Cyberpix S550V |
201 | spca506 0734:043b 3DeMon USB Capture aka | 206 | spca506 0734:043b 3DeMon USB Capture aka |
207 | ov519 0813:0002 Dual Mode USB Camera Plus | ||
202 | spca500 084d:0003 D-Link DSC-350 | 208 | spca500 084d:0003 D-Link DSC-350 |
203 | spca500 08ca:0103 Aiptek PocketDV | 209 | spca500 08ca:0103 Aiptek PocketDV |
204 | sunplus 08ca:0104 Aiptek PocketDVII 1.3 | 210 | sunplus 08ca:0104 Aiptek PocketDVII 1.3 |
@@ -236,15 +242,15 @@ pac7311 093a:2603 Philips SPC 500 NC | |||
236 | pac7311 093a:2608 Trust WB-3300p | 242 | pac7311 093a:2608 Trust WB-3300p |
237 | pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 | 243 | pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 |
238 | pac7311 093a:260f SnakeCam | 244 | pac7311 093a:260f SnakeCam |
239 | pac7311 093a:2620 Apollo AC-905 | 245 | pac7302 093a:2620 Apollo AC-905 |
240 | pac7311 093a:2621 PAC731x | 246 | pac7302 093a:2621 PAC731x |
241 | pac7311 093a:2622 Genius Eye 312 | 247 | pac7302 093a:2622 Genius Eye 312 |
242 | pac7311 093a:2624 PAC7302 | 248 | pac7302 093a:2624 PAC7302 |
243 | pac7311 093a:2626 Labtec 2200 | 249 | pac7302 093a:2626 Labtec 2200 |
244 | pac7311 093a:2628 Genius iLook 300 | 250 | pac7302 093a:2628 Genius iLook 300 |
245 | pac7311 093a:2629 Genious iSlim 300 | 251 | pac7302 093a:2629 Genious iSlim 300 |
246 | pac7311 093a:262a Webcam 300k | 252 | pac7302 093a:262a Webcam 300k |
247 | pac7311 093a:262c Philips SPC 230 NC | 253 | pac7302 093a:262c Philips SPC 230 NC |
248 | jeilinj 0979:0280 Sakar 57379 | 254 | jeilinj 0979:0280 Sakar 57379 |
249 | zc3xx 0ac8:0302 Z-star Vimicro zc0302 | 255 | zc3xx 0ac8:0302 Z-star Vimicro zc0302 |
250 | vc032x 0ac8:0321 Vimicro generic vc0321 | 256 | vc032x 0ac8:0321 Vimicro generic vc0321 |
@@ -259,6 +265,7 @@ vc032x 0ac8:c002 Sony embedded vimicro | |||
259 | vc032x 0ac8:c301 Samsung Q1 Ultra Premium | 265 | vc032x 0ac8:c301 Samsung Q1 Ultra Premium |
260 | spca508 0af9:0010 Hama USB Sightcam 100 | 266 | spca508 0af9:0010 Hama USB Sightcam 100 |
261 | spca508 0af9:0011 Hama USB Sightcam 100 | 267 | spca508 0af9:0011 Hama USB Sightcam 100 |
268 | ov519 0b62:0059 iBOT2 Webcam | ||
262 | sonixb 0c45:6001 Genius VideoCAM NB | 269 | sonixb 0c45:6001 Genius VideoCAM NB |
263 | sonixb 0c45:6005 Microdia Sweex Mini Webcam | 270 | sonixb 0c45:6005 Microdia Sweex Mini Webcam |
264 | sonixb 0c45:6007 Sonix sn9c101 + Tas5110D | 271 | sonixb 0c45:6007 Sonix sn9c101 + Tas5110D |
@@ -318,8 +325,10 @@ sn9c20x 0c45:62b3 PC Camera (SN9C202 + OV9655) | |||
318 | sn9c20x 0c45:62bb PC Camera (SN9C202 + OV7660) | 325 | sn9c20x 0c45:62bb PC Camera (SN9C202 + OV7660) |
319 | sn9c20x 0c45:62bc PC Camera (SN9C202 + HV7131R) | 326 | sn9c20x 0c45:62bc PC Camera (SN9C202 + HV7131R) |
320 | sunplus 0d64:0303 Sunplus FashionCam DXG | 327 | sunplus 0d64:0303 Sunplus FashionCam DXG |
328 | ov519 0e96:c001 TRUST 380 USB2 SPACEC@M | ||
321 | etoms 102c:6151 Qcam Sangha CIF | 329 | etoms 102c:6151 Qcam Sangha CIF |
322 | etoms 102c:6251 Qcam xxxxxx VGA | 330 | etoms 102c:6251 Qcam xxxxxx VGA |
331 | ov519 1046:9967 W9967CF/W9968CF WebCam IC, Video Blaster WebCam Go | ||
323 | zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128 | 332 | zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128 |
324 | spca561 10fd:7e50 FlyCam Usb 100 | 333 | spca561 10fd:7e50 FlyCam Usb 100 |
325 | zc3xx 10fd:8050 Typhoon Webshot II USB 300k | 334 | zc3xx 10fd:8050 Typhoon Webshot II USB 300k |
@@ -332,7 +341,12 @@ spca501 1776:501c Arowana 300K CMOS Camera | |||
332 | t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops | 341 | t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops |
333 | vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC | 342 | vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC |
334 | pac207 2001:f115 D-Link DSB-C120 | 343 | pac207 2001:f115 D-Link DSB-C120 |
344 | sq905c 2770:9050 sq905c | ||
345 | sq905c 2770:905c DualCamera | ||
346 | sq905 2770:9120 Argus Digital Camera DC1512 | ||
347 | sq905c 2770:913d sq905c | ||
335 | spca500 2899:012c Toptro Industrial | 348 | spca500 2899:012c Toptro Industrial |
349 | ov519 8020:ef04 ov519 | ||
336 | spca508 8086:0110 Intel Easy PC Camera | 350 | spca508 8086:0110 Intel Easy PC Camera |
337 | spca500 8086:0630 Intel Pocket PC Camera | 351 | spca500 8086:0630 Intel Pocket PC Camera |
338 | spca506 99fa:8988 Grandtec V.cap | 352 | spca506 99fa:8988 Grandtec V.cap |
diff --git a/Documentation/video4linux/sh_mobile_ceu_camera.txt b/Documentation/video4linux/sh_mobile_ceu_camera.txt new file mode 100644 index 000000000000..2ae16349a78d --- /dev/null +++ b/Documentation/video4linux/sh_mobile_ceu_camera.txt | |||
@@ -0,0 +1,157 @@ | |||
1 | Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver | ||
2 | ======================================================================= | ||
3 | |||
4 | Terminology | ||
5 | ----------- | ||
6 | |||
7 | sensor scales: horizontal and vertical scales, configured by the sensor driver | ||
8 | host scales: -"- host driver | ||
9 | combined scales: sensor_scale * host_scale | ||
10 | |||
11 | |||
12 | Generic scaling / cropping scheme | ||
13 | --------------------------------- | ||
14 | |||
15 | -1-- | ||
16 | | | ||
17 | -2-- -\ | ||
18 | | --\ | ||
19 | | --\ | ||
20 | +-5-- -\ -- -3-- | ||
21 | | ---\ | ||
22 | | --- -4-- -\ | ||
23 | | -\ | ||
24 | | - -6-- | ||
25 | | | ||
26 | | - -6'- | ||
27 | | -/ | ||
28 | | --- -4'- -/ | ||
29 | | ---/ | ||
30 | +-5'- -/ | ||
31 | | -- -3'- | ||
32 | | --/ | ||
33 | | --/ | ||
34 | -2'- -/ | ||
35 | | | ||
36 | | | ||
37 | -1'- | ||
38 | |||
39 | Produced by user requests: | ||
40 | |||
41 | S_CROP(left / top = (5) - (1), width / height = (5') - (5)) | ||
42 | S_FMT(width / height = (6') - (6)) | ||
43 | |||
44 | Here: | ||
45 | |||
46 | (1) to (1') - whole max width or height | ||
47 | (1) to (2) - sensor cropped left or top | ||
48 | (2) to (2') - sensor cropped width or height | ||
49 | (3) to (3') - sensor scale | ||
50 | (3) to (4) - CEU cropped left or top | ||
51 | (4) to (4') - CEU cropped width or height | ||
52 | (5) to (5') - reverse sensor scale applied to CEU cropped width or height | ||
53 | (2) to (5) - reverse sensor scale applied to CEU cropped left or top | ||
54 | (6) to (6') - CEU scale - user window | ||
55 | |||
56 | |||
57 | S_FMT | ||
58 | ----- | ||
59 | |||
60 | Do not touch input rectangle - it is already optimal. | ||
61 | |||
62 | 1. Calculate current sensor scales: | ||
63 | |||
64 | scale_s = ((3') - (3)) / ((2') - (2)) | ||
65 | |||
66 | 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at | ||
67 | current sensor scales onto input window - this is user S_CROP: | ||
68 | |||
69 | width_u = (5') - (5) = ((4') - (4)) * scale_s | ||
70 | |||
71 | 3. Calculate new combined scales from "effective" input window to requested user | ||
72 | window: | ||
73 | |||
74 | scale_comb = width_u / ((6') - (6)) | ||
75 | |||
76 | 4. Calculate sensor output window by applying combined scales to real input | ||
77 | window: | ||
78 | |||
79 | width_s_out = ((2') - (2)) / scale_comb | ||
80 | |||
81 | 5. Apply iterative sensor S_FMT for sensor output window. | ||
82 | |||
83 | subdev->video_ops->s_fmt(.width = width_s_out) | ||
84 | |||
85 | 6. Retrieve sensor output window (g_fmt) | ||
86 | |||
87 | 7. Calculate new sensor scales: | ||
88 | |||
89 | scale_s_new = ((3')_new - (3)_new) / ((2') - (2)) | ||
90 | |||
91 | 8. Calculate new CEU crop - apply sensor scales to previously calculated | ||
92 | "effective" crop: | ||
93 | |||
94 | width_ceu = (4')_new - (4)_new = width_u / scale_s_new | ||
95 | left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new | ||
96 | |||
97 | 9. Use CEU cropping to crop to the new window: | ||
98 | |||
99 | ceu_crop(.width = width_ceu, .left = left_ceu) | ||
100 | |||
101 | 10. Use CEU scaling to scale to the requested user window: | ||
102 | |||
103 | scale_ceu = width_ceu / width | ||
104 | |||
105 | |||
106 | S_CROP | ||
107 | ------ | ||
108 | |||
109 | If old scale applied to new crop is invalid produce nearest new scale possible | ||
110 | |||
111 | 1. Calculate current combined scales. | ||
112 | |||
113 | scale_comb = (((4') - (4)) / ((6') - (6))) * (((2') - (2)) / ((3') - (3))) | ||
114 | |||
115 | 2. Apply iterative sensor S_CROP for new input window. | ||
116 | |||
117 | 3. If old combined scales applied to new crop produce an impossible user window, | ||
118 | adjust scales to produce nearest possible window. | ||
119 | |||
120 | width_u_out = ((5') - (5)) / scale_comb | ||
121 | |||
122 | if (width_u_out > max) | ||
123 | scale_comb = ((5') - (5)) / max; | ||
124 | else if (width_u_out < min) | ||
125 | scale_comb = ((5') - (5)) / min; | ||
126 | |||
127 | 4. Issue G_CROP to retrieve actual input window. | ||
128 | |||
129 | 5. Using actual input window and calculated combined scales calculate sensor | ||
130 | target output window. | ||
131 | |||
132 | width_s_out = ((3') - (3)) = ((2') - (2)) / scale_comb | ||
133 | |||
134 | 6. Apply iterative S_FMT for new sensor target output window. | ||
135 | |||
136 | 7. Issue G_FMT to retrieve the actual sensor output window. | ||
137 | |||
138 | 8. Calculate sensor scales. | ||
139 | |||
140 | scale_s = ((3') - (3)) / ((2') - (2)) | ||
141 | |||
142 | 9. Calculate sensor output subwindow to be cropped on CEU by applying sensor | ||
143 | scales to the requested window. | ||
144 | |||
145 | width_ceu = ((5') - (5)) / scale_s | ||
146 | |||
147 | 10. Use CEU cropping for above calculated window. | ||
148 | |||
149 | 11. Calculate CEU scales from sensor scales from results of (10) and user window | ||
150 | from (3) | ||
151 | |||
152 | scale_ceu = calc_scale(((5') - (5)), &width_u_out) | ||
153 | |||
154 | 12. Apply CEU scales. | ||
155 | |||
156 | -- | ||
157 | Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index b806edaf3e75..74d677c8b036 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt | |||
@@ -561,6 +561,8 @@ video_device helper functions | |||
561 | 561 | ||
562 | There are a few useful helper functions: | 562 | There are a few useful helper functions: |
563 | 563 | ||
564 | - file/video_device private data | ||
565 | |||
564 | You can set/get driver private data in the video_device struct using: | 566 | You can set/get driver private data in the video_device struct using: |
565 | 567 | ||
566 | void *video_get_drvdata(struct video_device *vdev); | 568 | void *video_get_drvdata(struct video_device *vdev); |
@@ -575,8 +577,7 @@ struct video_device *video_devdata(struct file *file); | |||
575 | 577 | ||
576 | returns the video_device belonging to the file struct. | 578 | returns the video_device belonging to the file struct. |
577 | 579 | ||
578 | The final helper function combines video_get_drvdata with | 580 | The video_drvdata function combines video_get_drvdata with video_devdata: |
579 | video_devdata: | ||
580 | 581 | ||
581 | void *video_drvdata(struct file *file); | 582 | void *video_drvdata(struct file *file); |
582 | 583 | ||
@@ -584,6 +585,17 @@ You can go from a video_device struct to the v4l2_device struct using: | |||
584 | 585 | ||
585 | struct v4l2_device *v4l2_dev = vdev->v4l2_dev; | 586 | struct v4l2_device *v4l2_dev = vdev->v4l2_dev; |
586 | 587 | ||
588 | - Device node name | ||
589 | |||
590 | The video_device node kernel name can be retrieved using | ||
591 | |||
592 | const char *video_device_node_name(struct video_device *vdev); | ||
593 | |||
594 | The name is used as a hint by userspace tools such as udev. The function | ||
595 | should be used where possible instead of accessing the video_device::num and | ||
596 | video_device::minor fields. | ||
597 | |||
598 | |||
587 | video buffer helper functions | 599 | video buffer helper functions |
588 | ----------------------------- | 600 | ----------------------------- |
589 | 601 | ||
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h index 5c75c1b2352a..9baae8afe8a3 100644 --- a/arch/alpha/include/asm/elf.h +++ b/arch/alpha/include/asm/elf.h | |||
@@ -81,7 +81,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; | |||
81 | #define ELF_DATA ELFDATA2LSB | 81 | #define ELF_DATA ELFDATA2LSB |
82 | #define ELF_ARCH EM_ALPHA | 82 | #define ELF_ARCH EM_ALPHA |
83 | 83 | ||
84 | #define USE_ELF_CORE_DUMP | ||
85 | #define ELF_EXEC_PAGESIZE 8192 | 84 | #define ELF_EXEC_PAGESIZE 8192 |
86 | 85 | ||
87 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 86 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 6aac3f5bb2f3..a399bb5730f1 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h | |||
@@ -101,7 +101,6 @@ extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int); | |||
101 | int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); | 101 | int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); |
102 | #define ELF_CORE_COPY_TASK_REGS dump_task_regs | 102 | #define ELF_CORE_COPY_TASK_REGS dump_task_regs |
103 | 103 | ||
104 | #define USE_ELF_CORE_DUMP | ||
105 | #define ELF_EXEC_PAGESIZE 4096 | 104 | #define ELF_EXEC_PAGESIZE 4096 |
106 | 105 | ||
107 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 106 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 62b98bffc158..07de8db14581 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c | |||
@@ -339,6 +339,15 @@ static struct davinci_mmc_config da850_mmc_config = { | |||
339 | .version = MMC_CTLR_VERSION_2, | 339 | .version = MMC_CTLR_VERSION_2, |
340 | }; | 340 | }; |
341 | 341 | ||
342 | static void da850_panel_power_ctrl(int val) | ||
343 | { | ||
344 | /* lcd backlight */ | ||
345 | gpio_set_value(DA850_LCD_BL_PIN, val); | ||
346 | |||
347 | /* lcd power */ | ||
348 | gpio_set_value(DA850_LCD_PWR_PIN, val); | ||
349 | } | ||
350 | |||
342 | static int da850_lcd_hw_init(void) | 351 | static int da850_lcd_hw_init(void) |
343 | { | 352 | { |
344 | int status; | 353 | int status; |
@@ -356,17 +365,11 @@ static int da850_lcd_hw_init(void) | |||
356 | gpio_direction_output(DA850_LCD_BL_PIN, 0); | 365 | gpio_direction_output(DA850_LCD_BL_PIN, 0); |
357 | gpio_direction_output(DA850_LCD_PWR_PIN, 0); | 366 | gpio_direction_output(DA850_LCD_PWR_PIN, 0); |
358 | 367 | ||
359 | /* disable lcd backlight */ | 368 | /* Switch off panel power and backlight */ |
360 | gpio_set_value(DA850_LCD_BL_PIN, 0); | 369 | da850_panel_power_ctrl(0); |
361 | |||
362 | /* disable lcd power */ | ||
363 | gpio_set_value(DA850_LCD_PWR_PIN, 0); | ||
364 | |||
365 | /* enable lcd power */ | ||
366 | gpio_set_value(DA850_LCD_PWR_PIN, 1); | ||
367 | 370 | ||
368 | /* enable lcd backlight */ | 371 | /* Switch on panel power and backlight */ |
369 | gpio_set_value(DA850_LCD_BL_PIN, 1); | 372 | da850_panel_power_ctrl(1); |
370 | 373 | ||
371 | return 0; | 374 | return 0; |
372 | } | 375 | } |
@@ -674,6 +677,7 @@ static __init void da850_evm_init(void) | |||
674 | pr_warning("da850_evm_init: lcd initialization failed: %d\n", | 677 | pr_warning("da850_evm_init: lcd initialization failed: %d\n", |
675 | ret); | 678 | ret); |
676 | 679 | ||
680 | sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl, | ||
677 | ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata); | 681 | ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata); |
678 | if (ret) | 682 | if (ret) |
679 | pr_warning("da850_evm_init: lcdc registration failed: %d\n", | 683 | pr_warning("da850_evm_init: lcdc registration failed: %d\n", |
diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index d5d1d41c600a..3b3159b710d4 100644 --- a/arch/avr32/include/asm/elf.h +++ b/arch/avr32/include/asm/elf.h | |||
@@ -77,7 +77,6 @@ typedef struct user_fpu_struct elf_fpregset_t; | |||
77 | #endif | 77 | #endif |
78 | #define ELF_ARCH EM_AVR32 | 78 | #define ELF_ARCH EM_AVR32 |
79 | 79 | ||
80 | #define USE_ELF_CORE_DUMP | ||
81 | #define ELF_EXEC_PAGESIZE 4096 | 80 | #define ELF_EXEC_PAGESIZE 4096 |
82 | 81 | ||
83 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 82 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/blackfin/include/asm/bfin-lq035q1.h b/arch/blackfin/include/asm/bfin-lq035q1.h new file mode 100644 index 000000000000..57bc21ac2296 --- /dev/null +++ b/arch/blackfin/include/asm/bfin-lq035q1.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 | ||
3 | * | ||
4 | * Copyright 2008-2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #ifndef BFIN_LQ035Q1_H | ||
9 | #define BFIN_LQ035Q1_H | ||
10 | |||
11 | #define LQ035_RL (0 << 8) /* Right -> Left Scan */ | ||
12 | #define LQ035_LR (1 << 8) /* Left -> Right Scan */ | ||
13 | #define LQ035_TB (1 << 9) /* Top -> Botton Scan */ | ||
14 | #define LQ035_BT (0 << 9) /* Botton -> Top Scan */ | ||
15 | #define LQ035_BGR (1 << 11) /* Use BGR format */ | ||
16 | #define LQ035_RGB (0 << 11) /* Use RGB format */ | ||
17 | #define LQ035_NORM (1 << 13) /* Reversal */ | ||
18 | #define LQ035_REV (0 << 13) /* Reversal */ | ||
19 | |||
20 | struct bfin_lq035q1fb_disp_info { | ||
21 | |||
22 | unsigned mode; | ||
23 | /* GPIOs */ | ||
24 | int use_bl; | ||
25 | unsigned gpio_bl; | ||
26 | }; | ||
27 | |||
28 | #endif /* BFIN_LQ035Q1_H */ | ||
diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h index 8e0764c81eaf..5b50f0ecacf8 100644 --- a/arch/blackfin/include/asm/elf.h +++ b/arch/blackfin/include/asm/elf.h | |||
@@ -55,7 +55,6 @@ do { \ | |||
55 | _regs->p2 = _dynamic_addr; \ | 55 | _regs->p2 = _dynamic_addr; \ |
56 | } while(0) | 56 | } while(0) |
57 | 57 | ||
58 | #define USE_ELF_CORE_DUMP | ||
59 | #define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC | 58 | #define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC |
60 | #define ELF_EXEC_PAGESIZE 4096 | 59 | #define ELF_EXEC_PAGESIZE 4096 |
61 | 60 | ||
diff --git a/arch/cris/include/asm/elf.h b/arch/cris/include/asm/elf.h index 0f51b10b9f4f..8a3d8e2b33c1 100644 --- a/arch/cris/include/asm/elf.h +++ b/arch/cris/include/asm/elf.h | |||
@@ -64,8 +64,6 @@ typedef unsigned long elf_fpregset_t; | |||
64 | #define EF_CRIS_VARIANT_COMMON_V10_V32 0x00000004 | 64 | #define EF_CRIS_VARIANT_COMMON_V10_V32 0x00000004 |
65 | /* End of excerpt from {binutils}/include/elf/cris.h. */ | 65 | /* End of excerpt from {binutils}/include/elf/cris.h. */ |
66 | 66 | ||
67 | #define USE_ELF_CORE_DUMP | ||
68 | |||
69 | #define ELF_EXEC_PAGESIZE 8192 | 67 | #define ELF_EXEC_PAGESIZE 8192 |
70 | 68 | ||
71 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 69 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/frv/include/asm/elf.h b/arch/frv/include/asm/elf.h index 7bbf6e47f8c8..c3819804a74b 100644 --- a/arch/frv/include/asm/elf.h +++ b/arch/frv/include/asm/elf.h | |||
@@ -115,7 +115,6 @@ do { \ | |||
115 | __kernel_frame0_ptr->gr29 = 0; \ | 115 | __kernel_frame0_ptr->gr29 = 0; \ |
116 | } while(0) | 116 | } while(0) |
117 | 117 | ||
118 | #define USE_ELF_CORE_DUMP | ||
119 | #define CORE_DUMP_USE_REGSET | 118 | #define CORE_DUMP_USE_REGSET |
120 | #define ELF_FDPIC_CORE_EFLAGS EF_FRV_FDPIC | 119 | #define ELF_FDPIC_CORE_EFLAGS EF_FRV_FDPIC |
121 | #define ELF_EXEC_PAGESIZE 16384 | 120 | #define ELF_EXEC_PAGESIZE 16384 |
diff --git a/arch/h8300/include/asm/elf.h b/arch/h8300/include/asm/elf.h index 94e2284c8816..c24fa250d653 100644 --- a/arch/h8300/include/asm/elf.h +++ b/arch/h8300/include/asm/elf.h | |||
@@ -34,7 +34,6 @@ typedef unsigned long elf_fpregset_t; | |||
34 | 34 | ||
35 | #define ELF_PLAT_INIT(_r) _r->er1 = 0 | 35 | #define ELF_PLAT_INIT(_r) _r->er1 = 0 |
36 | 36 | ||
37 | #define USE_ELF_CORE_DUMP | ||
38 | #define ELF_EXEC_PAGESIZE 4096 | 37 | #define ELF_EXEC_PAGESIZE 4096 |
39 | 38 | ||
40 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 39 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/ia64/ia32/elfcore32.h b/arch/ia64/ia32/elfcore32.h index 9a3abf58cea3..657725742617 100644 --- a/arch/ia64/ia32/elfcore32.h +++ b/arch/ia64/ia32/elfcore32.h | |||
@@ -11,8 +11,6 @@ | |||
11 | #include <asm/intrinsics.h> | 11 | #include <asm/intrinsics.h> |
12 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
13 | 13 | ||
14 | #define USE_ELF_CORE_DUMP 1 | ||
15 | |||
16 | /* Override elfcore.h */ | 14 | /* Override elfcore.h */ |
17 | #define _LINUX_ELFCORE_H 1 | 15 | #define _LINUX_ELFCORE_H 1 |
18 | typedef unsigned int elf_greg_t; | 16 | typedef unsigned int elf_greg_t; |
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 8d3c79cd81e7..7d09a09cdaad 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h | |||
@@ -73,7 +73,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) | |||
73 | if (!dev->dma_mask) | 73 | if (!dev->dma_mask) |
74 | return 0; | 74 | return 0; |
75 | 75 | ||
76 | return addr + size <= *dev->dma_mask; | 76 | return addr + size - 1 <= *dev->dma_mask; |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | 79 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) |
diff --git a/arch/ia64/include/asm/elf.h b/arch/ia64/include/asm/elf.h index 86eddee029cb..e14108b19c09 100644 --- a/arch/ia64/include/asm/elf.h +++ b/arch/ia64/include/asm/elf.h | |||
@@ -25,7 +25,6 @@ | |||
25 | #define ELF_DATA ELFDATA2LSB | 25 | #define ELF_DATA ELFDATA2LSB |
26 | #define ELF_ARCH EM_IA_64 | 26 | #define ELF_ARCH EM_IA_64 |
27 | 27 | ||
28 | #define USE_ELF_CORE_DUMP | ||
29 | #define CORE_DUMP_USE_REGSET | 28 | #define CORE_DUMP_USE_REGSET |
30 | 29 | ||
31 | /* Least-significant four bits of ELF header's e_flags are OS-specific. The bits are | 30 | /* Least-significant four bits of ELF header's e_flags are OS-specific. The bits are |
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h index 0d9d16e2d949..cc8335eb3110 100644 --- a/arch/ia64/include/asm/io.h +++ b/arch/ia64/include/asm/io.h | |||
@@ -424,6 +424,8 @@ __writeq (unsigned long val, volatile void __iomem *addr) | |||
424 | extern void __iomem * ioremap(unsigned long offset, unsigned long size); | 424 | extern void __iomem * ioremap(unsigned long offset, unsigned long size); |
425 | extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); | 425 | extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); |
426 | extern void iounmap (volatile void __iomem *addr); | 426 | extern void iounmap (volatile void __iomem *addr); |
427 | extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size); | ||
428 | extern void early_iounmap (volatile void __iomem *addr, unsigned long size); | ||
427 | 429 | ||
428 | /* | 430 | /* |
429 | * String version of IO memory access ops: | 431 | * String version of IO memory access ops: |
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c index 2a140627dfd6..3dccdd8eb275 100644 --- a/arch/ia64/mm/ioremap.c +++ b/arch/ia64/mm/ioremap.c | |||
@@ -22,6 +22,12 @@ __ioremap (unsigned long phys_addr) | |||
22 | } | 22 | } |
23 | 23 | ||
24 | void __iomem * | 24 | void __iomem * |
25 | early_ioremap (unsigned long phys_addr, unsigned long size) | ||
26 | { | ||
27 | return __ioremap(phys_addr); | ||
28 | } | ||
29 | |||
30 | void __iomem * | ||
25 | ioremap (unsigned long phys_addr, unsigned long size) | 31 | ioremap (unsigned long phys_addr, unsigned long size) |
26 | { | 32 | { |
27 | void __iomem *addr; | 33 | void __iomem *addr; |
@@ -102,6 +108,11 @@ ioremap_nocache (unsigned long phys_addr, unsigned long size) | |||
102 | EXPORT_SYMBOL(ioremap_nocache); | 108 | EXPORT_SYMBOL(ioremap_nocache); |
103 | 109 | ||
104 | void | 110 | void |
111 | early_iounmap (volatile void __iomem *addr, unsigned long size) | ||
112 | { | ||
113 | } | ||
114 | |||
115 | void | ||
105 | iounmap (volatile void __iomem *addr) | 116 | iounmap (volatile void __iomem *addr) |
106 | { | 117 | { |
107 | if (REGION_NUMBER(addr) == RGN_GATE) | 118 | if (REGION_NUMBER(addr) == RGN_GATE) |
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index 35b2a27d2e77..efb454534e52 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <linux/bitmap.h> | ||
12 | #include <asm/sn/sn_sal.h> | 13 | #include <asm/sn/sn_sal.h> |
13 | #include <asm/sn/addrs.h> | 14 | #include <asm/sn/addrs.h> |
14 | #include <asm/sn/io.h> | 15 | #include <asm/sn/io.h> |
@@ -369,7 +370,7 @@ tioca_dma_d48(struct pci_dev *pdev, u64 paddr) | |||
369 | static dma_addr_t | 370 | static dma_addr_t |
370 | tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size) | 371 | tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size) |
371 | { | 372 | { |
372 | int i, ps, ps_shift, entry, entries, mapsize, last_entry; | 373 | int ps, ps_shift, entry, entries, mapsize; |
373 | u64 xio_addr, end_xio_addr; | 374 | u64 xio_addr, end_xio_addr; |
374 | struct tioca_common *tioca_common; | 375 | struct tioca_common *tioca_common; |
375 | struct tioca_kernel *tioca_kern; | 376 | struct tioca_kernel *tioca_kern; |
@@ -410,23 +411,13 @@ tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size) | |||
410 | map = tioca_kern->ca_pcigart_pagemap; | 411 | map = tioca_kern->ca_pcigart_pagemap; |
411 | mapsize = tioca_kern->ca_pcigart_entries; | 412 | mapsize = tioca_kern->ca_pcigart_entries; |
412 | 413 | ||
413 | entry = find_first_zero_bit(map, mapsize); | 414 | entry = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0); |
414 | while (entry < mapsize) { | 415 | if (entry >= mapsize) { |
415 | last_entry = find_next_bit(map, mapsize, entry); | ||
416 | |||
417 | if (last_entry - entry >= entries) | ||
418 | break; | ||
419 | |||
420 | entry = find_next_zero_bit(map, mapsize, last_entry); | ||
421 | } | ||
422 | |||
423 | if (entry > mapsize) { | ||
424 | kfree(ca_dmamap); | 416 | kfree(ca_dmamap); |
425 | goto map_return; | 417 | goto map_return; |
426 | } | 418 | } |
427 | 419 | ||
428 | for (i = 0; i < entries; i++) | 420 | bitmap_set(map, entry, entries); |
429 | set_bit(entry + i, map); | ||
430 | 421 | ||
431 | bus_addr = tioca_kern->ca_pciap_base + (entry * ps); | 422 | bus_addr = tioca_kern->ca_pciap_base + (entry * ps); |
432 | 423 | ||
diff --git a/arch/m32r/include/asm/elf.h b/arch/m32r/include/asm/elf.h index 0cc34c94bf2b..2f85412ef730 100644 --- a/arch/m32r/include/asm/elf.h +++ b/arch/m32r/include/asm/elf.h | |||
@@ -102,7 +102,6 @@ typedef elf_fpreg_t elf_fpregset_t; | |||
102 | */ | 102 | */ |
103 | #define ELF_PLAT_INIT(_r, load_addr) (_r)->r0 = 0 | 103 | #define ELF_PLAT_INIT(_r, load_addr) (_r)->r0 = 0 |
104 | 104 | ||
105 | #define USE_ELF_CORE_DUMP | ||
106 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 105 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
107 | 106 | ||
108 | /* | 107 | /* |
diff --git a/arch/m68k/include/asm/elf.h b/arch/m68k/include/asm/elf.h index 0b0f49eb876b..01c193d91412 100644 --- a/arch/m68k/include/asm/elf.h +++ b/arch/m68k/include/asm/elf.h | |||
@@ -59,7 +59,6 @@ typedef struct user_m68kfp_struct elf_fpregset_t; | |||
59 | is actually used on ASV. */ | 59 | is actually used on ASV. */ |
60 | #define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 | 60 | #define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 |
61 | 61 | ||
62 | #define USE_ELF_CORE_DUMP | ||
63 | #ifndef CONFIG_SUN3 | 62 | #ifndef CONFIG_SUN3 |
64 | #define ELF_EXEC_PAGESIZE 4096 | 63 | #define ELF_EXEC_PAGESIZE 4096 |
65 | #else | 64 | #else |
diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h index f92fc0dda006..7d4acf2b278e 100644 --- a/arch/microblaze/include/asm/elf.h +++ b/arch/microblaze/include/asm/elf.h | |||
@@ -77,7 +77,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; | |||
77 | #define ELF_DATA ELFDATA2MSB | 77 | #define ELF_DATA ELFDATA2MSB |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | #define USE_ELF_CORE_DUMP | ||
81 | #define ELF_EXEC_PAGESIZE 4096 | 80 | #define ELF_EXEC_PAGESIZE 4096 |
82 | 81 | ||
83 | 82 | ||
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 7990694cda22..7a6a35dbe529 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h | |||
@@ -326,7 +326,6 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); | |||
326 | #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) \ | 326 | #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) \ |
327 | dump_task_fpu(tsk, elf_fpregs) | 327 | dump_task_fpu(tsk, elf_fpregs) |
328 | 328 | ||
329 | #define USE_ELF_CORE_DUMP | ||
330 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 329 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
331 | 330 | ||
332 | /* This yields a mask that user programs can use to figure out what | 331 | /* This yields a mask that user programs can use to figure out what |
diff --git a/arch/mn10300/include/asm/elf.h b/arch/mn10300/include/asm/elf.h index 75a70aa9fd6f..e5fa97cd9a14 100644 --- a/arch/mn10300/include/asm/elf.h +++ b/arch/mn10300/include/asm/elf.h | |||
@@ -77,7 +77,6 @@ do { \ | |||
77 | _ur->a1 = 0; _ur->a0 = 0; _ur->d1 = 0; _ur->d0 = 0; \ | 77 | _ur->a1 = 0; _ur->a0 = 0; _ur->d1 = 0; _ur->d0 = 0; \ |
78 | } while (0) | 78 | } while (0) |
79 | 79 | ||
80 | #define USE_ELF_CORE_DUMP | ||
81 | #define CORE_DUMP_USE_REGSET | 80 | #define CORE_DUMP_USE_REGSET |
82 | #define ELF_EXEC_PAGESIZE 4096 | 81 | #define ELF_EXEC_PAGESIZE 4096 |
83 | 82 | ||
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 9c802eb4be84..19f6cb1a4a1c 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h | |||
@@ -328,7 +328,6 @@ struct pt_regs; /* forward declaration... */ | |||
328 | such function. */ | 328 | such function. */ |
329 | #define ELF_PLAT_INIT(_r, load_addr) _r->gr[23] = 0 | 329 | #define ELF_PLAT_INIT(_r, load_addr) _r->gr[23] = 0 |
330 | 330 | ||
331 | #define USE_ELF_CORE_DUMP | ||
332 | #define ELF_EXEC_PAGESIZE 4096 | 331 | #define ELF_EXEC_PAGESIZE 4096 |
333 | 332 | ||
334 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 333 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index e281daebddca..80a973bb9e71 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h | |||
@@ -197,7 +197,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) | |||
197 | if (!dev->dma_mask) | 197 | if (!dev->dma_mask) |
198 | return 0; | 198 | return 0; |
199 | 199 | ||
200 | return addr + size <= *dev->dma_mask; | 200 | return addr + size - 1 <= *dev->dma_mask; |
201 | } | 201 | } |
202 | 202 | ||
203 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | 203 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) |
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index 014a624f4c8e..17828ad411eb 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h | |||
@@ -170,7 +170,6 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG]; | |||
170 | #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH) | 170 | #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH) |
171 | #define compat_elf_check_arch(x) ((x)->e_machine == EM_PPC) | 171 | #define compat_elf_check_arch(x) ((x)->e_machine == EM_PPC) |
172 | 172 | ||
173 | #define USE_ELF_CORE_DUMP | ||
174 | #define CORE_DUMP_USE_REGSET | 173 | #define CORE_DUMP_USE_REGSET |
175 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 174 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
176 | 175 | ||
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 8c341490cfc5..cbd759e3cd78 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h | |||
@@ -140,6 +140,8 @@ extern void user_enable_single_step(struct task_struct *); | |||
140 | extern void user_enable_block_step(struct task_struct *); | 140 | extern void user_enable_block_step(struct task_struct *); |
141 | extern void user_disable_single_step(struct task_struct *); | 141 | extern void user_disable_single_step(struct task_struct *); |
142 | 142 | ||
143 | #define ARCH_HAS_USER_SINGLE_STEP_INFO | ||
144 | |||
143 | #endif /* __ASSEMBLY__ */ | 145 | #endif /* __ASSEMBLY__ */ |
144 | 146 | ||
145 | #endif /* __KERNEL__ */ | 147 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index fd51578e29dd..5547ae6e6b0b 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/dma-mapping.h> | 32 | #include <linux/dma-mapping.h> |
33 | #include <linux/bitops.h> | 33 | #include <linux/bitmap.h> |
34 | #include <linux/iommu-helper.h> | 34 | #include <linux/iommu-helper.h> |
35 | #include <linux/crash_dump.h> | 35 | #include <linux/crash_dump.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
@@ -251,7 +251,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
251 | } | 251 | } |
252 | 252 | ||
253 | ppc_md.tce_free(tbl, entry, npages); | 253 | ppc_md.tce_free(tbl, entry, npages); |
254 | iommu_area_free(tbl->it_map, free_entry, npages); | 254 | bitmap_clear(tbl->it_map, free_entry, npages); |
255 | } | 255 | } |
256 | 256 | ||
257 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | 257 | static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 804f0f30f227..d069ff8a7e03 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -174,6 +174,15 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | void user_single_step_siginfo(struct task_struct *tsk, | ||
178 | struct pt_regs *regs, siginfo_t *info) | ||
179 | { | ||
180 | memset(info, 0, sizeof(*info)); | ||
181 | info->si_signo = SIGTRAP; | ||
182 | info->si_code = TRAP_TRACE; | ||
183 | info->si_addr = (void __user *)regs->nip; | ||
184 | } | ||
185 | |||
177 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | 186 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) |
178 | { | 187 | { |
179 | siginfo_t info; | 188 | siginfo_t info; |
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index e885442c1dfe..354d42616c7e 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
@@ -155,7 +155,6 @@ extern unsigned int vdso_enabled; | |||
155 | } while (0) | 155 | } while (0) |
156 | 156 | ||
157 | #define CORE_DUMP_USE_REGSET | 157 | #define CORE_DUMP_USE_REGSET |
158 | #define USE_ELF_CORE_DUMP | ||
159 | #define ELF_EXEC_PAGESIZE 4096 | 158 | #define ELF_EXEC_PAGESIZE 4096 |
160 | 159 | ||
161 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 160 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/score/include/asm/elf.h b/arch/score/include/asm/elf.h index 43526d9fda93..f478ce94181f 100644 --- a/arch/score/include/asm/elf.h +++ b/arch/score/include/asm/elf.h | |||
@@ -61,7 +61,6 @@ struct task_struct; | |||
61 | struct pt_regs; | 61 | struct pt_regs; |
62 | 62 | ||
63 | #define CORE_DUMP_USE_REGSET | 63 | #define CORE_DUMP_USE_REGSET |
64 | #define USE_ELF_CORE_DUMP | ||
65 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 64 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
66 | 65 | ||
67 | /* This yields a mask that user programs can use to figure out what | 66 | /* This yields a mask that user programs can use to figure out what |
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index cf9dc12dfeb1..7a9f69663f1a 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
@@ -316,20 +316,23 @@ static struct soc_camera_platform_info camera_info = { | |||
316 | .format_name = "UYVY", | 316 | .format_name = "UYVY", |
317 | .format_depth = 16, | 317 | .format_depth = 16, |
318 | .format = { | 318 | .format = { |
319 | .pixelformat = V4L2_PIX_FMT_UYVY, | 319 | .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, |
320 | .colorspace = V4L2_COLORSPACE_SMPTE170M, | 320 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
321 | .field = V4L2_FIELD_NONE, | ||
321 | .width = 640, | 322 | .width = 640, |
322 | .height = 480, | 323 | .height = 480, |
323 | }, | 324 | }, |
324 | .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | | 325 | .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | |
325 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8, | 326 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8, |
326 | .set_capture = camera_set_capture, | 327 | .set_capture = camera_set_capture, |
327 | .link = { | 328 | }; |
328 | .bus_id = 0, | 329 | |
329 | .add_device = ap325rxa_camera_add, | 330 | struct soc_camera_link camera_link = { |
330 | .del_device = ap325rxa_camera_del, | 331 | .bus_id = 0, |
331 | .module_name = "soc_camera_platform", | 332 | .add_device = ap325rxa_camera_add, |
332 | }, | 333 | .del_device = ap325rxa_camera_del, |
334 | .module_name = "soc_camera_platform", | ||
335 | .priv = &camera_info, | ||
333 | }; | 336 | }; |
334 | 337 | ||
335 | static void dummy_release(struct device *dev) | 338 | static void dummy_release(struct device *dev) |
@@ -347,7 +350,7 @@ static struct platform_device camera_device = { | |||
347 | static int ap325rxa_camera_add(struct soc_camera_link *icl, | 350 | static int ap325rxa_camera_add(struct soc_camera_link *icl, |
348 | struct device *dev) | 351 | struct device *dev) |
349 | { | 352 | { |
350 | if (icl != &camera_info.link || camera_probe() <= 0) | 353 | if (icl != &camera_link || camera_probe() <= 0) |
351 | return -ENODEV; | 354 | return -ENODEV; |
352 | 355 | ||
353 | camera_info.dev = dev; | 356 | camera_info.dev = dev; |
@@ -357,7 +360,7 @@ static int ap325rxa_camera_add(struct soc_camera_link *icl, | |||
357 | 360 | ||
358 | static void ap325rxa_camera_del(struct soc_camera_link *icl) | 361 | static void ap325rxa_camera_del(struct soc_camera_link *icl) |
359 | { | 362 | { |
360 | if (icl != &camera_info.link) | 363 | if (icl != &camera_link) |
361 | return; | 364 | return; |
362 | 365 | ||
363 | platform_device_unregister(&camera_device); | 366 | platform_device_unregister(&camera_device); |
@@ -470,13 +473,15 @@ static struct ov772x_camera_info ov7725_info = { | |||
470 | .buswidth = SOCAM_DATAWIDTH_8, | 473 | .buswidth = SOCAM_DATAWIDTH_8, |
471 | .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP, | 474 | .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP, |
472 | .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0), | 475 | .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0), |
473 | .link = { | 476 | }; |
474 | .bus_id = 0, | 477 | |
475 | .power = ov7725_power, | 478 | static struct soc_camera_link ov7725_link = { |
476 | .board_info = &ap325rxa_i2c_camera[0], | 479 | .bus_id = 0, |
477 | .i2c_adapter_id = 0, | 480 | .power = ov7725_power, |
478 | .module_name = "ov772x", | 481 | .board_info = &ap325rxa_i2c_camera[0], |
479 | }, | 482 | .i2c_adapter_id = 0, |
483 | .module_name = "ov772x", | ||
484 | .priv = &ov7725_info, | ||
480 | }; | 485 | }; |
481 | 486 | ||
482 | static struct platform_device ap325rxa_camera[] = { | 487 | static struct platform_device ap325rxa_camera[] = { |
@@ -484,13 +489,13 @@ static struct platform_device ap325rxa_camera[] = { | |||
484 | .name = "soc-camera-pdrv", | 489 | .name = "soc-camera-pdrv", |
485 | .id = 0, | 490 | .id = 0, |
486 | .dev = { | 491 | .dev = { |
487 | .platform_data = &ov7725_info.link, | 492 | .platform_data = &ov7725_link, |
488 | }, | 493 | }, |
489 | }, { | 494 | }, { |
490 | .name = "soc-camera-pdrv", | 495 | .name = "soc-camera-pdrv", |
491 | .id = 1, | 496 | .id = 1, |
492 | .dev = { | 497 | .dev = { |
493 | .platform_data = &camera_info.link, | 498 | .platform_data = &camera_link, |
494 | }, | 499 | }, |
495 | }, | 500 | }, |
496 | }; | 501 | }; |
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 87438d6603d6..9038d768a525 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/input/sh_keysc.h> | 19 | #include <linux/input/sh_keysc.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/usb/r8a66597.h> | 21 | #include <linux/usb/r8a66597.h> |
22 | #include <media/rj54n1cb0c.h> | ||
22 | #include <media/soc_camera.h> | 23 | #include <media/soc_camera.h> |
23 | #include <media/sh_mobile_ceu.h> | 24 | #include <media/sh_mobile_ceu.h> |
24 | #include <video/sh_mobile_lcdc.h> | 25 | #include <video/sh_mobile_lcdc.h> |
@@ -255,6 +256,9 @@ static struct i2c_board_info kfr2r09_i2c_camera = { | |||
255 | 256 | ||
256 | static struct clk *camera_clk; | 257 | static struct clk *camera_clk; |
257 | 258 | ||
259 | /* set VIO_CKO clock to 25MHz */ | ||
260 | #define CEU_MCLK_FREQ 25000000 | ||
261 | |||
258 | #define DRVCRB 0xA405018C | 262 | #define DRVCRB 0xA405018C |
259 | static int camera_power(struct device *dev, int mode) | 263 | static int camera_power(struct device *dev, int mode) |
260 | { | 264 | { |
@@ -267,8 +271,7 @@ static int camera_power(struct device *dev, int mode) | |||
267 | if (IS_ERR(camera_clk)) | 271 | if (IS_ERR(camera_clk)) |
268 | return PTR_ERR(camera_clk); | 272 | return PTR_ERR(camera_clk); |
269 | 273 | ||
270 | /* set VIO_CKO clock to 25MHz */ | 274 | rate = clk_round_rate(camera_clk, CEU_MCLK_FREQ); |
271 | rate = clk_round_rate(camera_clk, 25000000); | ||
272 | ret = clk_set_rate(camera_clk, rate); | 275 | ret = clk_set_rate(camera_clk, rate); |
273 | if (ret < 0) | 276 | if (ret < 0) |
274 | goto eclkrate; | 277 | goto eclkrate; |
@@ -318,11 +321,17 @@ eclkrate: | |||
318 | return ret; | 321 | return ret; |
319 | } | 322 | } |
320 | 323 | ||
324 | static struct rj54n1_pdata rj54n1_priv = { | ||
325 | .mclk_freq = CEU_MCLK_FREQ, | ||
326 | .ioctl_high = false, | ||
327 | }; | ||
328 | |||
321 | static struct soc_camera_link rj54n1_link = { | 329 | static struct soc_camera_link rj54n1_link = { |
322 | .power = camera_power, | 330 | .power = camera_power, |
323 | .board_info = &kfr2r09_i2c_camera, | 331 | .board_info = &kfr2r09_i2c_camera, |
324 | .i2c_adapter_id = 1, | 332 | .i2c_adapter_id = 1, |
325 | .module_name = "rj54n1cb0c", | 333 | .module_name = "rj54n1cb0c", |
334 | .priv = &rj54n1_priv, | ||
326 | }; | 335 | }; |
327 | 336 | ||
328 | static struct platform_device kfr2r09_camera = { | 337 | static struct platform_device kfr2r09_camera = { |
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 9099b6da9957..507c77be476d 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -432,23 +432,27 @@ static struct i2c_board_info migor_i2c_camera[] = { | |||
432 | 432 | ||
433 | static struct ov772x_camera_info ov7725_info = { | 433 | static struct ov772x_camera_info ov7725_info = { |
434 | .buswidth = SOCAM_DATAWIDTH_8, | 434 | .buswidth = SOCAM_DATAWIDTH_8, |
435 | .link = { | 435 | }; |
436 | .power = ov7725_power, | 436 | |
437 | .board_info = &migor_i2c_camera[0], | 437 | static struct soc_camera_link ov7725_link = { |
438 | .i2c_adapter_id = 0, | 438 | .power = ov7725_power, |
439 | .module_name = "ov772x", | 439 | .board_info = &migor_i2c_camera[0], |
440 | }, | 440 | .i2c_adapter_id = 0, |
441 | .module_name = "ov772x", | ||
442 | .priv = &ov7725_info, | ||
441 | }; | 443 | }; |
442 | 444 | ||
443 | static struct tw9910_video_info tw9910_info = { | 445 | static struct tw9910_video_info tw9910_info = { |
444 | .buswidth = SOCAM_DATAWIDTH_8, | 446 | .buswidth = SOCAM_DATAWIDTH_8, |
445 | .mpout = TW9910_MPO_FIELD, | 447 | .mpout = TW9910_MPO_FIELD, |
446 | .link = { | 448 | }; |
447 | .power = tw9910_power, | 449 | |
448 | .board_info = &migor_i2c_camera[1], | 450 | static struct soc_camera_link tw9910_link = { |
449 | .i2c_adapter_id = 0, | 451 | .power = tw9910_power, |
450 | .module_name = "tw9910", | 452 | .board_info = &migor_i2c_camera[1], |
451 | } | 453 | .i2c_adapter_id = 0, |
454 | .module_name = "tw9910", | ||
455 | .priv = &tw9910_info, | ||
452 | }; | 456 | }; |
453 | 457 | ||
454 | static struct platform_device migor_camera[] = { | 458 | static struct platform_device migor_camera[] = { |
@@ -456,13 +460,13 @@ static struct platform_device migor_camera[] = { | |||
456 | .name = "soc-camera-pdrv", | 460 | .name = "soc-camera-pdrv", |
457 | .id = 0, | 461 | .id = 0, |
458 | .dev = { | 462 | .dev = { |
459 | .platform_data = &ov7725_info.link, | 463 | .platform_data = &ov7725_link, |
460 | }, | 464 | }, |
461 | }, { | 465 | }, { |
462 | .name = "soc-camera-pdrv", | 466 | .name = "soc-camera-pdrv", |
463 | .id = 1, | 467 | .id = 1, |
464 | .dev = { | 468 | .dev = { |
465 | .platform_data = &tw9910_info.link, | 469 | .platform_data = &tw9910_link, |
466 | }, | 470 | }, |
467 | }, | 471 | }, |
468 | }; | 472 | }; |
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index ccb1d93bb043..ac04255022b6 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h | |||
@@ -114,7 +114,6 @@ typedef struct user_fpu_struct elf_fpregset_t; | |||
114 | */ | 114 | */ |
115 | #define CORE_DUMP_USE_REGSET | 115 | #define CORE_DUMP_USE_REGSET |
116 | 116 | ||
117 | #define USE_ELF_CORE_DUMP | ||
118 | #define ELF_FDPIC_CORE_EFLAGS EF_SH_FDPIC | 117 | #define ELF_FDPIC_CORE_EFLAGS EF_SH_FDPIC |
119 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 118 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
120 | 119 | ||
diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h index 381a1b5256d6..4269ca6ad18a 100644 --- a/arch/sparc/include/asm/elf_32.h +++ b/arch/sparc/include/asm/elf_32.h | |||
@@ -104,8 +104,6 @@ typedef struct { | |||
104 | #define ELF_CLASS ELFCLASS32 | 104 | #define ELF_CLASS ELFCLASS32 |
105 | #define ELF_DATA ELFDATA2MSB | 105 | #define ELF_DATA ELFDATA2MSB |
106 | 106 | ||
107 | #define USE_ELF_CORE_DUMP | ||
108 | |||
109 | #define ELF_EXEC_PAGESIZE 4096 | 107 | #define ELF_EXEC_PAGESIZE 4096 |
110 | 108 | ||
111 | 109 | ||
diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h index d42e393078c4..ff66bb88537b 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h | |||
@@ -152,7 +152,6 @@ typedef struct { | |||
152 | (x)->e_machine == EM_SPARC32PLUS) | 152 | (x)->e_machine == EM_SPARC32PLUS) |
153 | #define compat_start_thread start_thread32 | 153 | #define compat_start_thread start_thread32 |
154 | 154 | ||
155 | #define USE_ELF_CORE_DUMP | ||
156 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 155 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
157 | 156 | ||
158 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 157 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 7690cc219ecc..5fad94950e76 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/iommu-helper.h> | 13 | #include <linux/iommu-helper.h> |
14 | #include <linux/bitmap.h> | ||
14 | 15 | ||
15 | #ifdef CONFIG_PCI | 16 | #ifdef CONFIG_PCI |
16 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
@@ -169,7 +170,7 @@ void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long np | |||
169 | 170 | ||
170 | entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; | 171 | entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; |
171 | 172 | ||
172 | iommu_area_free(arena->map, entry, npages); | 173 | bitmap_clear(arena->map, entry, npages); |
173 | } | 174 | } |
174 | 175 | ||
175 | int iommu_table_init(struct iommu *iommu, int tsbsize, | 176 | int iommu_table_init(struct iommu *iommu, int tsbsize, |
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index e0ba898e30cf..df39a0f0d27a 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/bitmap.h> | ||
17 | 18 | ||
18 | #include <asm/hypervisor.h> | 19 | #include <asm/hypervisor.h> |
19 | #include <asm/iommu.h> | 20 | #include <asm/iommu.h> |
@@ -1875,7 +1876,7 @@ EXPORT_SYMBOL(ldc_read); | |||
1875 | static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) | 1876 | static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) |
1876 | { | 1877 | { |
1877 | struct iommu_arena *arena = &iommu->arena; | 1878 | struct iommu_arena *arena = &iommu->arena; |
1878 | unsigned long n, i, start, end, limit; | 1879 | unsigned long n, start, end, limit; |
1879 | int pass; | 1880 | int pass; |
1880 | 1881 | ||
1881 | limit = arena->limit; | 1882 | limit = arena->limit; |
@@ -1883,7 +1884,7 @@ static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) | |||
1883 | pass = 0; | 1884 | pass = 0; |
1884 | 1885 | ||
1885 | again: | 1886 | again: |
1886 | n = find_next_zero_bit(arena->map, limit, start); | 1887 | n = bitmap_find_next_zero_area(arena->map, limit, start, npages, 0); |
1887 | end = n + npages; | 1888 | end = n + npages; |
1888 | if (unlikely(end >= limit)) { | 1889 | if (unlikely(end >= limit)) { |
1889 | if (likely(pass < 1)) { | 1890 | if (likely(pass < 1)) { |
@@ -1896,16 +1897,7 @@ again: | |||
1896 | return -1; | 1897 | return -1; |
1897 | } | 1898 | } |
1898 | } | 1899 | } |
1899 | 1900 | bitmap_set(arena->map, n, npages); | |
1900 | for (i = n; i < end; i++) { | ||
1901 | if (test_bit(i, arena->map)) { | ||
1902 | start = i + 1; | ||
1903 | goto again; | ||
1904 | } | ||
1905 | } | ||
1906 | |||
1907 | for (i = n; i < end; i++) | ||
1908 | __set_bit(i, arena->map); | ||
1909 | 1901 | ||
1910 | arena->hint = end; | 1902 | arena->hint = end; |
1911 | 1903 | ||
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 2ffacd67c424..a89baf0d875a 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <linux/scatterlist.h> | 19 | #include <linux/scatterlist.h> |
20 | #include <linux/bitmap.h> | ||
20 | 21 | ||
21 | #include <asm/sections.h> | 22 | #include <asm/sections.h> |
22 | #include <asm/page.h> | 23 | #include <asm/page.h> |
@@ -1021,20 +1022,12 @@ static char *sun4c_lockarea(char *vaddr, unsigned long size) | |||
1021 | npages = (((unsigned long)vaddr & ~PAGE_MASK) + | 1022 | npages = (((unsigned long)vaddr & ~PAGE_MASK) + |
1022 | size + (PAGE_SIZE-1)) >> PAGE_SHIFT; | 1023 | size + (PAGE_SIZE-1)) >> PAGE_SHIFT; |
1023 | 1024 | ||
1024 | scan = 0; | ||
1025 | local_irq_save(flags); | 1025 | local_irq_save(flags); |
1026 | for (;;) { | 1026 | base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size, |
1027 | scan = find_next_zero_bit(sun4c_iobuffer_map, | 1027 | 0, npages, 0); |
1028 | iobuffer_map_size, scan); | 1028 | if (base >= iobuffer_map_size) |
1029 | if ((base = scan) + npages > iobuffer_map_size) goto abend; | 1029 | goto abend; |
1030 | for (;;) { | ||
1031 | if (scan >= base + npages) goto found; | ||
1032 | if (test_bit(scan, sun4c_iobuffer_map)) break; | ||
1033 | scan++; | ||
1034 | } | ||
1035 | } | ||
1036 | 1030 | ||
1037 | found: | ||
1038 | high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start; | 1031 | high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start; |
1039 | high = SUN4C_REAL_PGDIR_ALIGN(high); | 1032 | high = SUN4C_REAL_PGDIR_ALIGN(high); |
1040 | while (high > sun4c_iobuffer_high) { | 1033 | while (high > sun4c_iobuffer_high) { |
diff --git a/arch/um/sys-i386/asm/elf.h b/arch/um/sys-i386/asm/elf.h index d0da9d7c5371..770885472ed4 100644 --- a/arch/um/sys-i386/asm/elf.h +++ b/arch/um/sys-i386/asm/elf.h | |||
@@ -48,7 +48,6 @@ typedef struct user_i387_struct elf_fpregset_t; | |||
48 | PT_REGS_EAX(regs) = 0; \ | 48 | PT_REGS_EAX(regs) = 0; \ |
49 | } while (0) | 49 | } while (0) |
50 | 50 | ||
51 | #define USE_ELF_CORE_DUMP | ||
52 | #define ELF_EXEC_PAGESIZE 4096 | 51 | #define ELF_EXEC_PAGESIZE 4096 |
53 | 52 | ||
54 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) | 53 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) |
diff --git a/arch/um/sys-ppc/asm/elf.h b/arch/um/sys-ppc/asm/elf.h index af9463cd8ce5..8aacaf56508d 100644 --- a/arch/um/sys-ppc/asm/elf.h +++ b/arch/um/sys-ppc/asm/elf.h | |||
@@ -17,8 +17,6 @@ extern long elf_aux_hwcap; | |||
17 | #define ELF_CLASS ELFCLASS32 | 17 | #define ELF_CLASS ELFCLASS32 |
18 | #endif | 18 | #endif |
19 | 19 | ||
20 | #define USE_ELF_CORE_DUMP | ||
21 | |||
22 | #define R_386_NONE 0 | 20 | #define R_386_NONE 0 |
23 | #define R_386_32 1 | 21 | #define R_386_32 1 |
24 | #define R_386_PC32 2 | 22 | #define R_386_PC32 2 |
diff --git a/arch/um/sys-x86_64/asm/elf.h b/arch/um/sys-x86_64/asm/elf.h index 04b9e87c8dad..49655c83efd2 100644 --- a/arch/um/sys-x86_64/asm/elf.h +++ b/arch/um/sys-x86_64/asm/elf.h | |||
@@ -104,7 +104,6 @@ extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu); | |||
104 | clear_thread_flag(TIF_IA32); | 104 | clear_thread_flag(TIF_IA32); |
105 | #endif | 105 | #endif |
106 | 106 | ||
107 | #define USE_ELF_CORE_DUMP | ||
108 | #define ELF_EXEC_PAGESIZE 4096 | 107 | #define ELF_EXEC_PAGESIZE 4096 |
109 | 108 | ||
110 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) | 109 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) |
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 0f6c02f3b7d4..ac91eed21061 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h | |||
@@ -67,7 +67,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) | |||
67 | if (!dev->dma_mask) | 67 | if (!dev->dma_mask) |
68 | return 0; | 68 | return 0; |
69 | 69 | ||
70 | return addr + size <= *dev->dma_mask; | 70 | return addr + size - 1 <= *dev->dma_mask; |
71 | } | 71 | } |
72 | 72 | ||
73 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | 73 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) |
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 8a024babe5e6..b4501ee223ad 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h | |||
@@ -239,7 +239,6 @@ extern int force_personality32; | |||
239 | #endif /* !CONFIG_X86_32 */ | 239 | #endif /* !CONFIG_X86_32 */ |
240 | 240 | ||
241 | #define CORE_DUMP_USE_REGSET | 241 | #define CORE_DUMP_USE_REGSET |
242 | #define USE_ELF_CORE_DUMP | ||
243 | #define ELF_EXEC_PAGESIZE 4096 | 242 | #define ELF_EXEC_PAGESIZE 4096 |
244 | 243 | ||
245 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical | 244 | /* This is the location that an ET_DYN program is loaded if exec'ed. Typical |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 3d11fd0f44c5..9d369f680321 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -292,6 +292,8 @@ extern void user_enable_block_step(struct task_struct *); | |||
292 | #define arch_has_block_step() (boot_cpu_data.x86 >= 6) | 292 | #define arch_has_block_step() (boot_cpu_data.x86 >= 6) |
293 | #endif | 293 | #endif |
294 | 294 | ||
295 | #define ARCH_HAS_USER_SINGLE_STEP_INFO | ||
296 | |||
295 | struct user_desc; | 297 | struct user_desc; |
296 | extern int do_get_thread_area(struct task_struct *p, int idx, | 298 | extern int do_get_thread_area(struct task_struct *p, int idx, |
297 | struct user_desc __user *info); | 299 | struct user_desc __user *info); |
diff --git a/arch/x86/include/asm/uv/bios.h b/arch/x86/include/asm/uv/bios.h index 7ed17ff502b9..2751f3075d8b 100644 --- a/arch/x86/include/asm/uv/bios.h +++ b/arch/x86/include/asm/uv/bios.h | |||
@@ -76,15 +76,6 @@ union partition_info_u { | |||
76 | }; | 76 | }; |
77 | }; | 77 | }; |
78 | 78 | ||
79 | union uv_watchlist_u { | ||
80 | u64 val; | ||
81 | struct { | ||
82 | u64 blade : 16, | ||
83 | size : 32, | ||
84 | filler : 16; | ||
85 | }; | ||
86 | }; | ||
87 | |||
88 | enum uv_memprotect { | 79 | enum uv_memprotect { |
89 | UV_MEMPROT_RESTRICT_ACCESS, | 80 | UV_MEMPROT_RESTRICT_ACCESS, |
90 | UV_MEMPROT_ALLOW_AMO, | 81 | UV_MEMPROT_ALLOW_AMO, |
@@ -100,7 +91,7 @@ extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64); | |||
100 | 91 | ||
101 | extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *); | 92 | extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *); |
102 | extern s64 uv_bios_freq_base(u64, u64 *); | 93 | extern s64 uv_bios_freq_base(u64, u64 *); |
103 | extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int, | 94 | extern int uv_bios_mq_watchlist_alloc(unsigned long, unsigned int, |
104 | unsigned long *); | 95 | unsigned long *); |
105 | extern int uv_bios_mq_watchlist_free(int, int); | 96 | extern int uv_bios_mq_watchlist_free(int, int); |
106 | extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect); | 97 | extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect); |
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index d1414af98559..811bfabc80b7 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h | |||
@@ -172,6 +172,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); | |||
172 | #define UV_LOCAL_MMR_SIZE (64UL * 1024 * 1024) | 172 | #define UV_LOCAL_MMR_SIZE (64UL * 1024 * 1024) |
173 | #define UV_GLOBAL_MMR32_SIZE (64UL * 1024 * 1024) | 173 | #define UV_GLOBAL_MMR32_SIZE (64UL * 1024 * 1024) |
174 | 174 | ||
175 | #define UV_GLOBAL_GRU_MMR_BASE 0x4000000 | ||
176 | |||
175 | #define UV_GLOBAL_MMR32_PNODE_SHIFT 15 | 177 | #define UV_GLOBAL_MMR32_PNODE_SHIFT 15 |
176 | #define UV_GLOBAL_MMR64_PNODE_SHIFT 26 | 178 | #define UV_GLOBAL_MMR64_PNODE_SHIFT 26 |
177 | 179 | ||
@@ -232,6 +234,26 @@ static inline unsigned long uv_gpa(void *v) | |||
232 | return uv_soc_phys_ram_to_gpa(__pa(v)); | 234 | return uv_soc_phys_ram_to_gpa(__pa(v)); |
233 | } | 235 | } |
234 | 236 | ||
237 | /* Top two bits indicate the requested address is in MMR space. */ | ||
238 | static inline int | ||
239 | uv_gpa_in_mmr_space(unsigned long gpa) | ||
240 | { | ||
241 | return (gpa >> 62) == 0x3UL; | ||
242 | } | ||
243 | |||
244 | /* UV global physical address --> socket phys RAM */ | ||
245 | static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa) | ||
246 | { | ||
247 | unsigned long paddr = gpa & uv_hub_info->gpa_mask; | ||
248 | unsigned long remap_base = uv_hub_info->lowmem_remap_base; | ||
249 | unsigned long remap_top = uv_hub_info->lowmem_remap_top; | ||
250 | |||
251 | if (paddr >= remap_base && paddr < remap_base + remap_top) | ||
252 | paddr -= remap_base; | ||
253 | return paddr; | ||
254 | } | ||
255 | |||
256 | |||
235 | /* gnode -> pnode */ | 257 | /* gnode -> pnode */ |
236 | static inline unsigned long uv_gpa_to_gnode(unsigned long gpa) | 258 | static inline unsigned long uv_gpa_to_gnode(unsigned long gpa) |
237 | { | 259 | { |
@@ -308,6 +330,15 @@ static inline unsigned long uv_read_global_mmr64(int pnode, | |||
308 | } | 330 | } |
309 | 331 | ||
310 | /* | 332 | /* |
333 | * Global MMR space addresses when referenced by the GRU. (GRU does | ||
334 | * NOT use socket addressing). | ||
335 | */ | ||
336 | static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long offset) | ||
337 | { | ||
338 | return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val); | ||
339 | } | ||
340 | |||
341 | /* | ||
311 | * Access hub local MMRs. Faster than using global space but only local MMRs | 342 | * Access hub local MMRs. Faster than using global space but only local MMRs |
312 | * are accessible. | 343 | * are accessible. |
313 | */ | 344 | */ |
@@ -434,6 +465,14 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) | |||
434 | } | 465 | } |
435 | } | 466 | } |
436 | 467 | ||
468 | static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode) | ||
469 | { | ||
470 | return (1UL << UVH_IPI_INT_SEND_SHFT) | | ||
471 | ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) | | ||
472 | (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) | | ||
473 | (vector << UVH_IPI_INT_VECTOR_SHFT); | ||
474 | } | ||
475 | |||
437 | static inline void uv_hub_send_ipi(int pnode, int apicid, int vector) | 476 | static inline void uv_hub_send_ipi(int pnode, int apicid, int vector) |
438 | { | 477 | { |
439 | unsigned long val; | 478 | unsigned long val; |
@@ -442,10 +481,7 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector) | |||
442 | if (vector == NMI_VECTOR) | 481 | if (vector == NMI_VECTOR) |
443 | dmode = dest_NMI; | 482 | dmode = dest_NMI; |
444 | 483 | ||
445 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | | 484 | val = uv_hub_ipi_value(apicid, vector, dmode); |
446 | ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) | | ||
447 | (dmode << UVH_IPI_INT_DELIVERY_MODE_SHFT) | | ||
448 | (vector << UVH_IPI_INT_VECTOR_SHFT); | ||
449 | uv_write_global_mmr64(pnode, UVH_IPI_INT, val); | 485 | uv_write_global_mmr64(pnode, UVH_IPI_INT, val); |
450 | } | 486 | } |
451 | 487 | ||
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b990b5cc9541..23824fef789c 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/gfp.h> | 21 | #include <linux/gfp.h> |
22 | #include <linux/bitops.h> | 22 | #include <linux/bitmap.h> |
23 | #include <linux/debugfs.h> | 23 | #include <linux/debugfs.h> |
24 | #include <linux/scatterlist.h> | 24 | #include <linux/scatterlist.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
@@ -1162,7 +1162,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom, | |||
1162 | 1162 | ||
1163 | address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT; | 1163 | address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT; |
1164 | 1164 | ||
1165 | iommu_area_free(range->bitmap, address, pages); | 1165 | bitmap_clear(range->bitmap, address, pages); |
1166 | 1166 | ||
1167 | } | 1167 | } |
1168 | 1168 | ||
diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c index 63a88e1f987d..b0206a211b09 100644 --- a/arch/x86/kernel/bios_uv.c +++ b/arch/x86/kernel/bios_uv.c | |||
@@ -101,21 +101,17 @@ s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, | |||
101 | } | 101 | } |
102 | 102 | ||
103 | int | 103 | int |
104 | uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size, | 104 | uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size, |
105 | unsigned long *intr_mmr_offset) | 105 | unsigned long *intr_mmr_offset) |
106 | { | 106 | { |
107 | union uv_watchlist_u size_blade; | ||
108 | u64 watchlist; | 107 | u64 watchlist; |
109 | s64 ret; | 108 | s64 ret; |
110 | 109 | ||
111 | size_blade.size = mq_size; | ||
112 | size_blade.blade = blade; | ||
113 | |||
114 | /* | 110 | /* |
115 | * bios returns watchlist number or negative error number. | 111 | * bios returns watchlist number or negative error number. |
116 | */ | 112 | */ |
117 | ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr, | 113 | ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr, |
118 | size_blade.val, (u64)intr_mmr_offset, | 114 | mq_size, (u64)intr_mmr_offset, |
119 | (u64)&watchlist, 0); | 115 | (u64)&watchlist, 0); |
120 | if (ret < BIOS_STATUS_SUCCESS) | 116 | if (ret < BIOS_STATUS_SUCCESS) |
121 | return ret; | 117 | return ret; |
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index c563e4c8ff39..2bbde6078143 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/crash_dump.h> | 32 | #include <linux/crash_dump.h> |
33 | #include <linux/dma-mapping.h> | 33 | #include <linux/dma-mapping.h> |
34 | #include <linux/bitops.h> | 34 | #include <linux/bitmap.h> |
35 | #include <linux/pci_ids.h> | 35 | #include <linux/pci_ids.h> |
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
@@ -212,7 +212,7 @@ static void iommu_range_reserve(struct iommu_table *tbl, | |||
212 | 212 | ||
213 | spin_lock_irqsave(&tbl->it_lock, flags); | 213 | spin_lock_irqsave(&tbl->it_lock, flags); |
214 | 214 | ||
215 | iommu_area_reserve(tbl->it_map, index, npages); | 215 | bitmap_set(tbl->it_map, index, npages); |
216 | 216 | ||
217 | spin_unlock_irqrestore(&tbl->it_lock, flags); | 217 | spin_unlock_irqrestore(&tbl->it_lock, flags); |
218 | } | 218 | } |
@@ -303,7 +303,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
303 | 303 | ||
304 | spin_lock_irqsave(&tbl->it_lock, flags); | 304 | spin_lock_irqsave(&tbl->it_lock, flags); |
305 | 305 | ||
306 | iommu_area_free(tbl->it_map, entry, npages); | 306 | bitmap_clear(tbl->it_map, entry, npages); |
307 | 307 | ||
308 | spin_unlock_irqrestore(&tbl->it_lock, flags); | 308 | spin_unlock_irqrestore(&tbl->it_lock, flags); |
309 | } | 309 | } |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 56c0e730d3fe..34de53b46f87 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/topology.h> | 24 | #include <linux/topology.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/bitops.h> | 26 | #include <linux/bitmap.h> |
27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
28 | #include <linux/scatterlist.h> | 28 | #include <linux/scatterlist.h> |
29 | #include <linux/iommu-helper.h> | 29 | #include <linux/iommu-helper.h> |
@@ -126,7 +126,7 @@ static void free_iommu(unsigned long offset, int size) | |||
126 | unsigned long flags; | 126 | unsigned long flags; |
127 | 127 | ||
128 | spin_lock_irqsave(&iommu_bitmap_lock, flags); | 128 | spin_lock_irqsave(&iommu_bitmap_lock, flags); |
129 | iommu_area_free(iommu_gart_bitmap, offset, size); | 129 | bitmap_clear(iommu_gart_bitmap, offset, size); |
130 | if (offset >= next_bit) | 130 | if (offset >= next_bit) |
131 | next_bit = offset + size; | 131 | next_bit = offset + size; |
132 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); | 132 | spin_unlock_irqrestore(&iommu_bitmap_lock, flags); |
@@ -792,7 +792,7 @@ int __init gart_iommu_init(void) | |||
792 | * Out of IOMMU space handling. | 792 | * Out of IOMMU space handling. |
793 | * Reserve some invalid pages at the beginning of the GART. | 793 | * Reserve some invalid pages at the beginning of the GART. |
794 | */ | 794 | */ |
795 | iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES); | 795 | bitmap_set(iommu_gart_bitmap, 0, EMERGENCY_PAGES); |
796 | 796 | ||
797 | pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", | 797 | pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", |
798 | iommu_size >> 20); | 798 | iommu_size >> 20); |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 7079ddaf0731..2779321046bd 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1676,21 +1676,33 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
1676 | #endif | 1676 | #endif |
1677 | } | 1677 | } |
1678 | 1678 | ||
1679 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | 1679 | static void fill_sigtrap_info(struct task_struct *tsk, |
1680 | int error_code, int si_code) | 1680 | struct pt_regs *regs, |
1681 | int error_code, int si_code, | ||
1682 | struct siginfo *info) | ||
1681 | { | 1683 | { |
1682 | struct siginfo info; | ||
1683 | |||
1684 | tsk->thread.trap_no = 1; | 1684 | tsk->thread.trap_no = 1; |
1685 | tsk->thread.error_code = error_code; | 1685 | tsk->thread.error_code = error_code; |
1686 | 1686 | ||
1687 | memset(&info, 0, sizeof(info)); | 1687 | memset(info, 0, sizeof(*info)); |
1688 | info.si_signo = SIGTRAP; | 1688 | info->si_signo = SIGTRAP; |
1689 | info.si_code = si_code; | 1689 | info->si_code = si_code; |
1690 | info->si_addr = user_mode_vm(regs) ? (void __user *)regs->ip : NULL; | ||
1691 | } | ||
1690 | 1692 | ||
1691 | /* User-mode ip? */ | 1693 | void user_single_step_siginfo(struct task_struct *tsk, |
1692 | info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; | 1694 | struct pt_regs *regs, |
1695 | struct siginfo *info) | ||
1696 | { | ||
1697 | fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info); | ||
1698 | } | ||
1693 | 1699 | ||
1700 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | ||
1701 | int error_code, int si_code) | ||
1702 | { | ||
1703 | struct siginfo info; | ||
1704 | |||
1705 | fill_sigtrap_info(tsk, regs, error_code, si_code, &info); | ||
1694 | /* Send us the fake SIGTRAP */ | 1706 | /* Send us the fake SIGTRAP */ |
1695 | force_sig_info(SIGTRAP, &info, tsk); | 1707 | force_sig_info(SIGTRAP, &info, tsk); |
1696 | } | 1708 | } |
@@ -1755,29 +1767,22 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs) | |||
1755 | 1767 | ||
1756 | asmregparm void syscall_trace_leave(struct pt_regs *regs) | 1768 | asmregparm void syscall_trace_leave(struct pt_regs *regs) |
1757 | { | 1769 | { |
1770 | bool step; | ||
1771 | |||
1758 | if (unlikely(current->audit_context)) | 1772 | if (unlikely(current->audit_context)) |
1759 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); | 1773 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); |
1760 | 1774 | ||
1761 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1775 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1762 | trace_sys_exit(regs, regs->ax); | 1776 | trace_sys_exit(regs, regs->ax); |
1763 | 1777 | ||
1764 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | ||
1765 | tracehook_report_syscall_exit(regs, 0); | ||
1766 | |||
1767 | /* | 1778 | /* |
1768 | * If TIF_SYSCALL_EMU is set, we only get here because of | 1779 | * If TIF_SYSCALL_EMU is set, we only get here because of |
1769 | * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). | 1780 | * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). |
1770 | * We already reported this syscall instruction in | 1781 | * We already reported this syscall instruction in |
1771 | * syscall_trace_enter(), so don't do any more now. | 1782 | * syscall_trace_enter(). |
1772 | */ | ||
1773 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) | ||
1774 | return; | ||
1775 | |||
1776 | /* | ||
1777 | * If we are single-stepping, synthesize a trap to follow the | ||
1778 | * system call instruction. | ||
1779 | */ | 1783 | */ |
1780 | if (test_thread_flag(TIF_SINGLESTEP) && | 1784 | step = unlikely(test_thread_flag(TIF_SINGLESTEP)) && |
1781 | tracehook_consider_fatal_signal(current, SIGTRAP)) | 1785 | !test_thread_flag(TIF_SYSCALL_EMU); |
1782 | send_sigtrap(current, regs, 0, TRAP_BRKPT); | 1786 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
1787 | tracehook_report_syscall_exit(regs, step); | ||
1783 | } | 1788 | } |
diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h index c3f53e755ca5..5eb6d695e987 100644 --- a/arch/xtensa/include/asm/elf.h +++ b/arch/xtensa/include/asm/elf.h | |||
@@ -123,7 +123,6 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *); | |||
123 | #define ELF_CLASS ELFCLASS32 | 123 | #define ELF_CLASS ELFCLASS32 |
124 | #define ELF_ARCH EM_XTENSA | 124 | #define ELF_ARCH EM_XTENSA |
125 | 125 | ||
126 | #define USE_ELF_CORE_DUMP | ||
127 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | 126 | #define ELF_EXEC_PAGESIZE PAGE_SIZE |
128 | 127 | ||
129 | /* | 128 | /* |
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 26a47dc88f61..53c524e7b829 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c | |||
@@ -285,6 +285,7 @@ static const struct file_operations efi_rtc_fops = { | |||
285 | .unlocked_ioctl = efi_rtc_ioctl, | 285 | .unlocked_ioctl = efi_rtc_ioctl, |
286 | .open = efi_rtc_open, | 286 | .open = efi_rtc_open, |
287 | .release = efi_rtc_close, | 287 | .release = efi_rtc_close, |
288 | .llseek = no_llseek, | ||
288 | }; | 289 | }; |
289 | 290 | ||
290 | static struct miscdevice efi_rtc_dev= { | 291 | static struct miscdevice efi_rtc_dev= { |
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 80704875794c..cf82fedae099 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c | |||
@@ -370,7 +370,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) | |||
370 | return SI_SM_IDLE; | 370 | return SI_SM_IDLE; |
371 | 371 | ||
372 | case KCS_START_OP: | 372 | case KCS_START_OP: |
373 | if (state != KCS_IDLE) { | 373 | if (state != KCS_IDLE_STATE) { |
374 | start_error_recovery(kcs, | 374 | start_error_recovery(kcs, |
375 | "State machine not idle at start"); | 375 | "State machine not idle at start"); |
376 | break; | 376 | break; |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 44203ff599da..1ae2de7d8b4f 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -339,7 +339,7 @@ static struct sysrq_key_op sysrq_term_op = { | |||
339 | 339 | ||
340 | static void moom_callback(struct work_struct *ignored) | 340 | static void moom_callback(struct work_struct *ignored) |
341 | { | 341 | { |
342 | out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0); | 342 | out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL); |
343 | } | 343 | } |
344 | 344 | ||
345 | static DECLARE_WORK(moom_work, moom_callback); | 345 | static DECLARE_WORK(moom_work, moom_callback); |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index e43fbc66aef0..50faa1fb0f06 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -164,6 +164,9 @@ module_param(default_utf8, int, S_IRUGO | S_IWUSR); | |||
164 | int global_cursor_default = -1; | 164 | int global_cursor_default = -1; |
165 | module_param(global_cursor_default, int, S_IRUGO | S_IWUSR); | 165 | module_param(global_cursor_default, int, S_IRUGO | S_IWUSR); |
166 | 166 | ||
167 | static int cur_default = CUR_DEFAULT; | ||
168 | module_param(cur_default, int, S_IRUGO | S_IWUSR); | ||
169 | |||
167 | /* | 170 | /* |
168 | * ignore_poke: don't unblank the screen when things are typed. This is | 171 | * ignore_poke: don't unblank the screen when things are typed. This is |
169 | * mainly for the privacy of braille terminal users. | 172 | * mainly for the privacy of braille terminal users. |
@@ -1636,7 +1639,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) | |||
1636 | /* do not do set_leds here because this causes an endless tasklet loop | 1639 | /* do not do set_leds here because this causes an endless tasklet loop |
1637 | when the keyboard hasn't been initialized yet */ | 1640 | when the keyboard hasn't been initialized yet */ |
1638 | 1641 | ||
1639 | vc->vc_cursor_type = CUR_DEFAULT; | 1642 | vc->vc_cursor_type = cur_default; |
1640 | vc->vc_complement_mask = vc->vc_s_complement_mask; | 1643 | vc->vc_complement_mask = vc->vc_s_complement_mask; |
1641 | 1644 | ||
1642 | default_attr(vc); | 1645 | default_attr(vc); |
@@ -1838,7 +1841,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | |||
1838 | if (vc->vc_par[0]) | 1841 | if (vc->vc_par[0]) |
1839 | vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); | 1842 | vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); |
1840 | else | 1843 | else |
1841 | vc->vc_cursor_type = CUR_DEFAULT; | 1844 | vc->vc_cursor_type = cur_default; |
1842 | return; | 1845 | return; |
1843 | } | 1846 | } |
1844 | break; | 1847 | break; |
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index c693fcc2213c..8fc91a019620 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c | |||
@@ -299,6 +299,12 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) | |||
299 | if (!handle_errors) | 299 | if (!handle_errors) |
300 | return; | 300 | return; |
301 | 301 | ||
302 | /* | ||
303 | * GART TLB error reporting is disabled by default. Bail out early. | ||
304 | */ | ||
305 | if (TLB_ERROR(ec) && !report_gart_errors) | ||
306 | return; | ||
307 | |||
302 | pr_emerg(" Northbridge Error, node %d", node_id); | 308 | pr_emerg(" Northbridge Error, node %d", node_id); |
303 | 309 | ||
304 | /* | 310 | /* |
@@ -310,10 +316,9 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) | |||
310 | if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) | 316 | if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) |
311 | pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); | 317 | pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); |
312 | } else { | 318 | } else { |
313 | pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); | 319 | pr_cont(", core: %d\n", fls((regs->nbsh & 0xf) - 1)); |
314 | } | 320 | } |
315 | 321 | ||
316 | |||
317 | pr_emerg("%s.\n", EXT_ERR_MSG(xec)); | 322 | pr_emerg("%s.\n", EXT_ERR_MSG(xec)); |
318 | 323 | ||
319 | if (BUS_ERROR(ec) && nb_bus_decoder) | 324 | if (BUS_ERROR(ec) && nb_bus_decoder) |
@@ -333,21 +338,6 @@ static void amd_decode_fr_mce(u64 mc5_status) | |||
333 | static inline void amd_decode_err_code(unsigned int ec) | 338 | static inline void amd_decode_err_code(unsigned int ec) |
334 | { | 339 | { |
335 | if (TLB_ERROR(ec)) { | 340 | if (TLB_ERROR(ec)) { |
336 | /* | ||
337 | * GART errors are intended to help graphics driver developers | ||
338 | * to detect bad GART PTEs. It is recommended by AMD to disable | ||
339 | * GART table walk error reporting by default[1] (currently | ||
340 | * being disabled in mce_cpu_quirks()) and according to the | ||
341 | * comment in mce_cpu_quirks(), such GART errors can be | ||
342 | * incorrectly triggered. We may see these errors anyway and | ||
343 | * unless requested by the user, they won't be reported. | ||
344 | * | ||
345 | * [1] section 13.10.1 on BIOS and Kernel Developers Guide for | ||
346 | * AMD NPT family 0Fh processors | ||
347 | */ | ||
348 | if (!report_gart_errors) | ||
349 | return; | ||
350 | |||
351 | pr_emerg(" Transaction: %s, Cache Level %s\n", | 341 | pr_emerg(" Transaction: %s, Cache Level %s\n", |
352 | TT_MSG(ec), LL_MSG(ec)); | 342 | TT_MSG(ec), LL_MSG(ec)); |
353 | } else if (MEM_ERROR(ec)) { | 343 | } else if (MEM_ERROR(ec)) { |
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 22db05a67bfb..7785d8ffa404 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c | |||
@@ -9,6 +9,11 @@ | |||
9 | * Intel 5100X Chipset Memory Controller Hub (MCH) - Datasheet | 9 | * Intel 5100X Chipset Memory Controller Hub (MCH) - Datasheet |
10 | * http://download.intel.com/design/chipsets/datashts/318378.pdf | 10 | * http://download.intel.com/design/chipsets/datashts/318378.pdf |
11 | * | 11 | * |
12 | * The intel 5100 has two independent channels. EDAC core currently | ||
13 | * can not reflect this configuration so instead the chip-select | ||
14 | * rows for each respective channel are layed out one after another, | ||
15 | * the first half belonging to channel 0, the second half belonging | ||
16 | * to channel 1. | ||
12 | */ | 17 | */ |
13 | #include <linux/module.h> | 18 | #include <linux/module.h> |
14 | #include <linux/init.h> | 19 | #include <linux/init.h> |
@@ -25,6 +30,8 @@ | |||
25 | 30 | ||
26 | /* device 16, func 1 */ | 31 | /* device 16, func 1 */ |
27 | #define I5100_MC 0x40 /* Memory Control Register */ | 32 | #define I5100_MC 0x40 /* Memory Control Register */ |
33 | #define I5100_MC_SCRBEN_MASK (1 << 7) | ||
34 | #define I5100_MC_SCRBDONE_MASK (1 << 4) | ||
28 | #define I5100_MS 0x44 /* Memory Status Register */ | 35 | #define I5100_MS 0x44 /* Memory Status Register */ |
29 | #define I5100_SPDDATA 0x48 /* Serial Presence Detect Status Reg */ | 36 | #define I5100_SPDDATA 0x48 /* Serial Presence Detect Status Reg */ |
30 | #define I5100_SPDCMD 0x4c /* Serial Presence Detect Command Reg */ | 37 | #define I5100_SPDCMD 0x4c /* Serial Presence Detect Command Reg */ |
@@ -72,11 +79,21 @@ | |||
72 | 79 | ||
73 | /* bit field accessors */ | 80 | /* bit field accessors */ |
74 | 81 | ||
82 | static inline u32 i5100_mc_scrben(u32 mc) | ||
83 | { | ||
84 | return mc >> 7 & 1; | ||
85 | } | ||
86 | |||
75 | static inline u32 i5100_mc_errdeten(u32 mc) | 87 | static inline u32 i5100_mc_errdeten(u32 mc) |
76 | { | 88 | { |
77 | return mc >> 5 & 1; | 89 | return mc >> 5 & 1; |
78 | } | 90 | } |
79 | 91 | ||
92 | static inline u32 i5100_mc_scrbdone(u32 mc) | ||
93 | { | ||
94 | return mc >> 4 & 1; | ||
95 | } | ||
96 | |||
80 | static inline u16 i5100_spddata_rdo(u16 a) | 97 | static inline u16 i5100_spddata_rdo(u16 a) |
81 | { | 98 | { |
82 | return a >> 15 & 1; | 99 | return a >> 15 & 1; |
@@ -265,42 +282,43 @@ static inline u32 i5100_recmemb_ras(u32 a) | |||
265 | } | 282 | } |
266 | 283 | ||
267 | /* some generic limits */ | 284 | /* some generic limits */ |
268 | #define I5100_MAX_RANKS_PER_CTLR 6 | 285 | #define I5100_MAX_RANKS_PER_CHAN 6 |
269 | #define I5100_MAX_CTLRS 2 | 286 | #define I5100_CHANNELS 2 |
270 | #define I5100_MAX_RANKS_PER_DIMM 4 | 287 | #define I5100_MAX_RANKS_PER_DIMM 4 |
271 | #define I5100_DIMM_ADDR_LINES (6 - 3) /* 64 bits / 8 bits per byte */ | 288 | #define I5100_DIMM_ADDR_LINES (6 - 3) /* 64 bits / 8 bits per byte */ |
272 | #define I5100_MAX_DIMM_SLOTS_PER_CTLR 4 | 289 | #define I5100_MAX_DIMM_SLOTS_PER_CHAN 4 |
273 | #define I5100_MAX_RANK_INTERLEAVE 4 | 290 | #define I5100_MAX_RANK_INTERLEAVE 4 |
274 | #define I5100_MAX_DMIRS 5 | 291 | #define I5100_MAX_DMIRS 5 |
292 | #define I5100_SCRUB_REFRESH_RATE (5 * 60 * HZ) | ||
275 | 293 | ||
276 | struct i5100_priv { | 294 | struct i5100_priv { |
277 | /* ranks on each dimm -- 0 maps to not present -- obtained via SPD */ | 295 | /* ranks on each dimm -- 0 maps to not present -- obtained via SPD */ |
278 | int dimm_numrank[I5100_MAX_CTLRS][I5100_MAX_DIMM_SLOTS_PER_CTLR]; | 296 | int dimm_numrank[I5100_CHANNELS][I5100_MAX_DIMM_SLOTS_PER_CHAN]; |
279 | 297 | ||
280 | /* | 298 | /* |
281 | * mainboard chip select map -- maps i5100 chip selects to | 299 | * mainboard chip select map -- maps i5100 chip selects to |
282 | * DIMM slot chip selects. In the case of only 4 ranks per | 300 | * DIMM slot chip selects. In the case of only 4 ranks per |
283 | * controller, the mapping is fairly obvious but not unique. | 301 | * channel, the mapping is fairly obvious but not unique. |
284 | * we map -1 -> NC and assume both controllers use the same | 302 | * we map -1 -> NC and assume both channels use the same |
285 | * map... | 303 | * map... |
286 | * | 304 | * |
287 | */ | 305 | */ |
288 | int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CTLR][I5100_MAX_RANKS_PER_DIMM]; | 306 | int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CHAN][I5100_MAX_RANKS_PER_DIMM]; |
289 | 307 | ||
290 | /* memory interleave range */ | 308 | /* memory interleave range */ |
291 | struct { | 309 | struct { |
292 | u64 limit; | 310 | u64 limit; |
293 | unsigned way[2]; | 311 | unsigned way[2]; |
294 | } mir[I5100_MAX_CTLRS]; | 312 | } mir[I5100_CHANNELS]; |
295 | 313 | ||
296 | /* adjusted memory interleave range register */ | 314 | /* adjusted memory interleave range register */ |
297 | unsigned amir[I5100_MAX_CTLRS]; | 315 | unsigned amir[I5100_CHANNELS]; |
298 | 316 | ||
299 | /* dimm interleave range */ | 317 | /* dimm interleave range */ |
300 | struct { | 318 | struct { |
301 | unsigned rank[I5100_MAX_RANK_INTERLEAVE]; | 319 | unsigned rank[I5100_MAX_RANK_INTERLEAVE]; |
302 | u64 limit; | 320 | u64 limit; |
303 | } dmir[I5100_MAX_CTLRS][I5100_MAX_DMIRS]; | 321 | } dmir[I5100_CHANNELS][I5100_MAX_DMIRS]; |
304 | 322 | ||
305 | /* memory technology registers... */ | 323 | /* memory technology registers... */ |
306 | struct { | 324 | struct { |
@@ -310,30 +328,33 @@ struct i5100_priv { | |||
310 | unsigned numbank; /* 2 or 3 lines */ | 328 | unsigned numbank; /* 2 or 3 lines */ |
311 | unsigned numrow; /* 13 .. 16 lines */ | 329 | unsigned numrow; /* 13 .. 16 lines */ |
312 | unsigned numcol; /* 11 .. 12 lines */ | 330 | unsigned numcol; /* 11 .. 12 lines */ |
313 | } mtr[I5100_MAX_CTLRS][I5100_MAX_RANKS_PER_CTLR]; | 331 | } mtr[I5100_CHANNELS][I5100_MAX_RANKS_PER_CHAN]; |
314 | 332 | ||
315 | u64 tolm; /* top of low memory in bytes */ | 333 | u64 tolm; /* top of low memory in bytes */ |
316 | unsigned ranksperctlr; /* number of ranks per controller */ | 334 | unsigned ranksperchan; /* number of ranks per channel */ |
317 | 335 | ||
318 | struct pci_dev *mc; /* device 16 func 1 */ | 336 | struct pci_dev *mc; /* device 16 func 1 */ |
319 | struct pci_dev *ch0mm; /* device 21 func 0 */ | 337 | struct pci_dev *ch0mm; /* device 21 func 0 */ |
320 | struct pci_dev *ch1mm; /* device 22 func 0 */ | 338 | struct pci_dev *ch1mm; /* device 22 func 0 */ |
339 | |||
340 | struct delayed_work i5100_scrubbing; | ||
341 | int scrub_enable; | ||
321 | }; | 342 | }; |
322 | 343 | ||
323 | /* map a rank/ctlr to a slot number on the mainboard */ | 344 | /* map a rank/chan to a slot number on the mainboard */ |
324 | static int i5100_rank_to_slot(const struct mem_ctl_info *mci, | 345 | static int i5100_rank_to_slot(const struct mem_ctl_info *mci, |
325 | int ctlr, int rank) | 346 | int chan, int rank) |
326 | { | 347 | { |
327 | const struct i5100_priv *priv = mci->pvt_info; | 348 | const struct i5100_priv *priv = mci->pvt_info; |
328 | int i; | 349 | int i; |
329 | 350 | ||
330 | for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) { | 351 | for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) { |
331 | int j; | 352 | int j; |
332 | const int numrank = priv->dimm_numrank[ctlr][i]; | 353 | const int numrank = priv->dimm_numrank[chan][i]; |
333 | 354 | ||
334 | for (j = 0; j < numrank; j++) | 355 | for (j = 0; j < numrank; j++) |
335 | if (priv->dimm_csmap[i][j] == rank) | 356 | if (priv->dimm_csmap[i][j] == rank) |
336 | return i * 2 + ctlr; | 357 | return i * 2 + chan; |
337 | } | 358 | } |
338 | 359 | ||
339 | return -1; | 360 | return -1; |
@@ -374,32 +395,32 @@ static const char *i5100_err_msg(unsigned err) | |||
374 | return "none"; | 395 | return "none"; |
375 | } | 396 | } |
376 | 397 | ||
377 | /* convert csrow index into a rank (per controller -- 0..5) */ | 398 | /* convert csrow index into a rank (per channel -- 0..5) */ |
378 | static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow) | 399 | static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow) |
379 | { | 400 | { |
380 | const struct i5100_priv *priv = mci->pvt_info; | 401 | const struct i5100_priv *priv = mci->pvt_info; |
381 | 402 | ||
382 | return csrow % priv->ranksperctlr; | 403 | return csrow % priv->ranksperchan; |
383 | } | 404 | } |
384 | 405 | ||
385 | /* convert csrow index into a controller (0..1) */ | 406 | /* convert csrow index into a channel (0..1) */ |
386 | static int i5100_csrow_to_cntlr(const struct mem_ctl_info *mci, int csrow) | 407 | static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow) |
387 | { | 408 | { |
388 | const struct i5100_priv *priv = mci->pvt_info; | 409 | const struct i5100_priv *priv = mci->pvt_info; |
389 | 410 | ||
390 | return csrow / priv->ranksperctlr; | 411 | return csrow / priv->ranksperchan; |
391 | } | 412 | } |
392 | 413 | ||
393 | static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci, | 414 | static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci, |
394 | int ctlr, int rank) | 415 | int chan, int rank) |
395 | { | 416 | { |
396 | const struct i5100_priv *priv = mci->pvt_info; | 417 | const struct i5100_priv *priv = mci->pvt_info; |
397 | 418 | ||
398 | return ctlr * priv->ranksperctlr + rank; | 419 | return chan * priv->ranksperchan + rank; |
399 | } | 420 | } |
400 | 421 | ||
401 | static void i5100_handle_ce(struct mem_ctl_info *mci, | 422 | static void i5100_handle_ce(struct mem_ctl_info *mci, |
402 | int ctlr, | 423 | int chan, |
403 | unsigned bank, | 424 | unsigned bank, |
404 | unsigned rank, | 425 | unsigned rank, |
405 | unsigned long syndrome, | 426 | unsigned long syndrome, |
@@ -407,12 +428,12 @@ static void i5100_handle_ce(struct mem_ctl_info *mci, | |||
407 | unsigned ras, | 428 | unsigned ras, |
408 | const char *msg) | 429 | const char *msg) |
409 | { | 430 | { |
410 | const int csrow = i5100_rank_to_csrow(mci, ctlr, rank); | 431 | const int csrow = i5100_rank_to_csrow(mci, chan, rank); |
411 | 432 | ||
412 | printk(KERN_ERR | 433 | printk(KERN_ERR |
413 | "CE ctlr %d, bank %u, rank %u, syndrome 0x%lx, " | 434 | "CE chan %d, bank %u, rank %u, syndrome 0x%lx, " |
414 | "cas %u, ras %u, csrow %u, label \"%s\": %s\n", | 435 | "cas %u, ras %u, csrow %u, label \"%s\": %s\n", |
415 | ctlr, bank, rank, syndrome, cas, ras, | 436 | chan, bank, rank, syndrome, cas, ras, |
416 | csrow, mci->csrows[csrow].channels[0].label, msg); | 437 | csrow, mci->csrows[csrow].channels[0].label, msg); |
417 | 438 | ||
418 | mci->ce_count++; | 439 | mci->ce_count++; |
@@ -421,7 +442,7 @@ static void i5100_handle_ce(struct mem_ctl_info *mci, | |||
421 | } | 442 | } |
422 | 443 | ||
423 | static void i5100_handle_ue(struct mem_ctl_info *mci, | 444 | static void i5100_handle_ue(struct mem_ctl_info *mci, |
424 | int ctlr, | 445 | int chan, |
425 | unsigned bank, | 446 | unsigned bank, |
426 | unsigned rank, | 447 | unsigned rank, |
427 | unsigned long syndrome, | 448 | unsigned long syndrome, |
@@ -429,23 +450,23 @@ static void i5100_handle_ue(struct mem_ctl_info *mci, | |||
429 | unsigned ras, | 450 | unsigned ras, |
430 | const char *msg) | 451 | const char *msg) |
431 | { | 452 | { |
432 | const int csrow = i5100_rank_to_csrow(mci, ctlr, rank); | 453 | const int csrow = i5100_rank_to_csrow(mci, chan, rank); |
433 | 454 | ||
434 | printk(KERN_ERR | 455 | printk(KERN_ERR |
435 | "UE ctlr %d, bank %u, rank %u, syndrome 0x%lx, " | 456 | "UE chan %d, bank %u, rank %u, syndrome 0x%lx, " |
436 | "cas %u, ras %u, csrow %u, label \"%s\": %s\n", | 457 | "cas %u, ras %u, csrow %u, label \"%s\": %s\n", |
437 | ctlr, bank, rank, syndrome, cas, ras, | 458 | chan, bank, rank, syndrome, cas, ras, |
438 | csrow, mci->csrows[csrow].channels[0].label, msg); | 459 | csrow, mci->csrows[csrow].channels[0].label, msg); |
439 | 460 | ||
440 | mci->ue_count++; | 461 | mci->ue_count++; |
441 | mci->csrows[csrow].ue_count++; | 462 | mci->csrows[csrow].ue_count++; |
442 | } | 463 | } |
443 | 464 | ||
444 | static void i5100_read_log(struct mem_ctl_info *mci, int ctlr, | 465 | static void i5100_read_log(struct mem_ctl_info *mci, int chan, |
445 | u32 ferr, u32 nerr) | 466 | u32 ferr, u32 nerr) |
446 | { | 467 | { |
447 | struct i5100_priv *priv = mci->pvt_info; | 468 | struct i5100_priv *priv = mci->pvt_info; |
448 | struct pci_dev *pdev = (ctlr) ? priv->ch1mm : priv->ch0mm; | 469 | struct pci_dev *pdev = (chan) ? priv->ch1mm : priv->ch0mm; |
449 | u32 dw; | 470 | u32 dw; |
450 | u32 dw2; | 471 | u32 dw2; |
451 | unsigned syndrome = 0; | 472 | unsigned syndrome = 0; |
@@ -484,7 +505,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int ctlr, | |||
484 | else | 505 | else |
485 | msg = i5100_err_msg(nerr); | 506 | msg = i5100_err_msg(nerr); |
486 | 507 | ||
487 | i5100_handle_ce(mci, ctlr, bank, rank, syndrome, cas, ras, msg); | 508 | i5100_handle_ce(mci, chan, bank, rank, syndrome, cas, ras, msg); |
488 | } | 509 | } |
489 | 510 | ||
490 | if (i5100_validlog_nrecmemvalid(dw)) { | 511 | if (i5100_validlog_nrecmemvalid(dw)) { |
@@ -506,7 +527,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int ctlr, | |||
506 | else | 527 | else |
507 | msg = i5100_err_msg(nerr); | 528 | msg = i5100_err_msg(nerr); |
508 | 529 | ||
509 | i5100_handle_ue(mci, ctlr, bank, rank, syndrome, cas, ras, msg); | 530 | i5100_handle_ue(mci, chan, bank, rank, syndrome, cas, ras, msg); |
510 | } | 531 | } |
511 | 532 | ||
512 | pci_write_config_dword(pdev, I5100_VALIDLOG, dw); | 533 | pci_write_config_dword(pdev, I5100_VALIDLOG, dw); |
@@ -534,6 +555,80 @@ static void i5100_check_error(struct mem_ctl_info *mci) | |||
534 | } | 555 | } |
535 | } | 556 | } |
536 | 557 | ||
558 | /* The i5100 chipset will scrub the entire memory once, then | ||
559 | * set a done bit. Continuous scrubbing is achieved by enqueing | ||
560 | * delayed work to a workqueue, checking every few minutes if | ||
561 | * the scrubbing has completed and if so reinitiating it. | ||
562 | */ | ||
563 | |||
564 | static void i5100_refresh_scrubbing(struct work_struct *work) | ||
565 | { | ||
566 | struct delayed_work *i5100_scrubbing = container_of(work, | ||
567 | struct delayed_work, | ||
568 | work); | ||
569 | struct i5100_priv *priv = container_of(i5100_scrubbing, | ||
570 | struct i5100_priv, | ||
571 | i5100_scrubbing); | ||
572 | u32 dw; | ||
573 | |||
574 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
575 | |||
576 | if (priv->scrub_enable) { | ||
577 | |||
578 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
579 | |||
580 | if (i5100_mc_scrbdone(dw)) { | ||
581 | dw |= I5100_MC_SCRBEN_MASK; | ||
582 | pci_write_config_dword(priv->mc, I5100_MC, dw); | ||
583 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
584 | } | ||
585 | |||
586 | schedule_delayed_work(&(priv->i5100_scrubbing), | ||
587 | I5100_SCRUB_REFRESH_RATE); | ||
588 | } | ||
589 | } | ||
590 | /* | ||
591 | * The bandwidth is based on experimentation, feel free to refine it. | ||
592 | */ | ||
593 | static int i5100_set_scrub_rate(struct mem_ctl_info *mci, | ||
594 | u32 *bandwidth) | ||
595 | { | ||
596 | struct i5100_priv *priv = mci->pvt_info; | ||
597 | u32 dw; | ||
598 | |||
599 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
600 | if (*bandwidth) { | ||
601 | priv->scrub_enable = 1; | ||
602 | dw |= I5100_MC_SCRBEN_MASK; | ||
603 | schedule_delayed_work(&(priv->i5100_scrubbing), | ||
604 | I5100_SCRUB_REFRESH_RATE); | ||
605 | } else { | ||
606 | priv->scrub_enable = 0; | ||
607 | dw &= ~I5100_MC_SCRBEN_MASK; | ||
608 | cancel_delayed_work(&(priv->i5100_scrubbing)); | ||
609 | } | ||
610 | pci_write_config_dword(priv->mc, I5100_MC, dw); | ||
611 | |||
612 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
613 | |||
614 | *bandwidth = 5900000 * i5100_mc_scrben(dw); | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int i5100_get_scrub_rate(struct mem_ctl_info *mci, | ||
620 | u32 *bandwidth) | ||
621 | { | ||
622 | struct i5100_priv *priv = mci->pvt_info; | ||
623 | u32 dw; | ||
624 | |||
625 | pci_read_config_dword(priv->mc, I5100_MC, &dw); | ||
626 | |||
627 | *bandwidth = 5900000 * i5100_mc_scrben(dw); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
537 | static struct pci_dev *pci_get_device_func(unsigned vendor, | 632 | static struct pci_dev *pci_get_device_func(unsigned vendor, |
538 | unsigned device, | 633 | unsigned device, |
539 | unsigned func) | 634 | unsigned func) |
@@ -557,19 +652,19 @@ static unsigned long __devinit i5100_npages(struct mem_ctl_info *mci, | |||
557 | int csrow) | 652 | int csrow) |
558 | { | 653 | { |
559 | struct i5100_priv *priv = mci->pvt_info; | 654 | struct i5100_priv *priv = mci->pvt_info; |
560 | const unsigned ctlr_rank = i5100_csrow_to_rank(mci, csrow); | 655 | const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow); |
561 | const unsigned ctlr = i5100_csrow_to_cntlr(mci, csrow); | 656 | const unsigned chan = i5100_csrow_to_chan(mci, csrow); |
562 | unsigned addr_lines; | 657 | unsigned addr_lines; |
563 | 658 | ||
564 | /* dimm present? */ | 659 | /* dimm present? */ |
565 | if (!priv->mtr[ctlr][ctlr_rank].present) | 660 | if (!priv->mtr[chan][chan_rank].present) |
566 | return 0ULL; | 661 | return 0ULL; |
567 | 662 | ||
568 | addr_lines = | 663 | addr_lines = |
569 | I5100_DIMM_ADDR_LINES + | 664 | I5100_DIMM_ADDR_LINES + |
570 | priv->mtr[ctlr][ctlr_rank].numcol + | 665 | priv->mtr[chan][chan_rank].numcol + |
571 | priv->mtr[ctlr][ctlr_rank].numrow + | 666 | priv->mtr[chan][chan_rank].numrow + |
572 | priv->mtr[ctlr][ctlr_rank].numbank; | 667 | priv->mtr[chan][chan_rank].numbank; |
573 | 668 | ||
574 | return (unsigned long) | 669 | return (unsigned long) |
575 | ((unsigned long long) (1ULL << addr_lines) / PAGE_SIZE); | 670 | ((unsigned long long) (1ULL << addr_lines) / PAGE_SIZE); |
@@ -581,11 +676,11 @@ static void __devinit i5100_init_mtr(struct mem_ctl_info *mci) | |||
581 | struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm }; | 676 | struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm }; |
582 | int i; | 677 | int i; |
583 | 678 | ||
584 | for (i = 0; i < I5100_MAX_CTLRS; i++) { | 679 | for (i = 0; i < I5100_CHANNELS; i++) { |
585 | int j; | 680 | int j; |
586 | struct pci_dev *pdev = mms[i]; | 681 | struct pci_dev *pdev = mms[i]; |
587 | 682 | ||
588 | for (j = 0; j < I5100_MAX_RANKS_PER_CTLR; j++) { | 683 | for (j = 0; j < I5100_MAX_RANKS_PER_CHAN; j++) { |
589 | const unsigned addr = | 684 | const unsigned addr = |
590 | (j < 4) ? I5100_MTR_0 + j * 2 : | 685 | (j < 4) ? I5100_MTR_0 + j * 2 : |
591 | I5100_MTR_4 + (j - 4) * 2; | 686 | I5100_MTR_4 + (j - 4) * 2; |
@@ -644,7 +739,6 @@ static int i5100_read_spd_byte(const struct mem_ctl_info *mci, | |||
644 | * fill dimm chip select map | 739 | * fill dimm chip select map |
645 | * | 740 | * |
646 | * FIXME: | 741 | * FIXME: |
647 | * o only valid for 4 ranks per controller | ||
648 | * o not the only way to may chip selects to dimm slots | 742 | * o not the only way to may chip selects to dimm slots |
649 | * o investigate if there is some way to obtain this map from the bios | 743 | * o investigate if there is some way to obtain this map from the bios |
650 | */ | 744 | */ |
@@ -653,9 +747,7 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci) | |||
653 | struct i5100_priv *priv = mci->pvt_info; | 747 | struct i5100_priv *priv = mci->pvt_info; |
654 | int i; | 748 | int i; |
655 | 749 | ||
656 | WARN_ON(priv->ranksperctlr != 4); | 750 | for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) { |
657 | |||
658 | for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) { | ||
659 | int j; | 751 | int j; |
660 | 752 | ||
661 | for (j = 0; j < I5100_MAX_RANKS_PER_DIMM; j++) | 753 | for (j = 0; j < I5100_MAX_RANKS_PER_DIMM; j++) |
@@ -663,12 +755,21 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci) | |||
663 | } | 755 | } |
664 | 756 | ||
665 | /* only 2 chip selects per slot... */ | 757 | /* only 2 chip selects per slot... */ |
666 | priv->dimm_csmap[0][0] = 0; | 758 | if (priv->ranksperchan == 4) { |
667 | priv->dimm_csmap[0][1] = 3; | 759 | priv->dimm_csmap[0][0] = 0; |
668 | priv->dimm_csmap[1][0] = 1; | 760 | priv->dimm_csmap[0][1] = 3; |
669 | priv->dimm_csmap[1][1] = 2; | 761 | priv->dimm_csmap[1][0] = 1; |
670 | priv->dimm_csmap[2][0] = 2; | 762 | priv->dimm_csmap[1][1] = 2; |
671 | priv->dimm_csmap[3][0] = 3; | 763 | priv->dimm_csmap[2][0] = 2; |
764 | priv->dimm_csmap[3][0] = 3; | ||
765 | } else { | ||
766 | priv->dimm_csmap[0][0] = 0; | ||
767 | priv->dimm_csmap[0][1] = 1; | ||
768 | priv->dimm_csmap[1][0] = 2; | ||
769 | priv->dimm_csmap[1][1] = 3; | ||
770 | priv->dimm_csmap[2][0] = 4; | ||
771 | priv->dimm_csmap[2][1] = 5; | ||
772 | } | ||
672 | } | 773 | } |
673 | 774 | ||
674 | static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev, | 775 | static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev, |
@@ -677,10 +778,10 @@ static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev, | |||
677 | struct i5100_priv *priv = mci->pvt_info; | 778 | struct i5100_priv *priv = mci->pvt_info; |
678 | int i; | 779 | int i; |
679 | 780 | ||
680 | for (i = 0; i < I5100_MAX_CTLRS; i++) { | 781 | for (i = 0; i < I5100_CHANNELS; i++) { |
681 | int j; | 782 | int j; |
682 | 783 | ||
683 | for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CTLR; j++) { | 784 | for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CHAN; j++) { |
684 | u8 rank; | 785 | u8 rank; |
685 | 786 | ||
686 | if (i5100_read_spd_byte(mci, i, j, 5, &rank) < 0) | 787 | if (i5100_read_spd_byte(mci, i, j, 5, &rank) < 0) |
@@ -720,7 +821,7 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev, | |||
720 | pci_read_config_word(pdev, I5100_AMIR_1, &w); | 821 | pci_read_config_word(pdev, I5100_AMIR_1, &w); |
721 | priv->amir[1] = w; | 822 | priv->amir[1] = w; |
722 | 823 | ||
723 | for (i = 0; i < I5100_MAX_CTLRS; i++) { | 824 | for (i = 0; i < I5100_CHANNELS; i++) { |
724 | int j; | 825 | int j; |
725 | 826 | ||
726 | for (j = 0; j < 5; j++) { | 827 | for (j = 0; j < 5; j++) { |
@@ -747,7 +848,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) | |||
747 | 848 | ||
748 | for (i = 0; i < mci->nr_csrows; i++) { | 849 | for (i = 0; i < mci->nr_csrows; i++) { |
749 | const unsigned long npages = i5100_npages(mci, i); | 850 | const unsigned long npages = i5100_npages(mci, i); |
750 | const unsigned cntlr = i5100_csrow_to_cntlr(mci, i); | 851 | const unsigned chan = i5100_csrow_to_chan(mci, i); |
751 | const unsigned rank = i5100_csrow_to_rank(mci, i); | 852 | const unsigned rank = i5100_csrow_to_rank(mci, i); |
752 | 853 | ||
753 | if (!npages) | 854 | if (!npages) |
@@ -765,7 +866,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) | |||
765 | mci->csrows[i].grain = 32; | 866 | mci->csrows[i].grain = 32; |
766 | mci->csrows[i].csrow_idx = i; | 867 | mci->csrows[i].csrow_idx = i; |
767 | mci->csrows[i].dtype = | 868 | mci->csrows[i].dtype = |
768 | (priv->mtr[cntlr][rank].width == 4) ? DEV_X4 : DEV_X8; | 869 | (priv->mtr[chan][rank].width == 4) ? DEV_X4 : DEV_X8; |
769 | mci->csrows[i].ue_count = 0; | 870 | mci->csrows[i].ue_count = 0; |
770 | mci->csrows[i].ce_count = 0; | 871 | mci->csrows[i].ce_count = 0; |
771 | mci->csrows[i].mtype = MEM_RDDR2; | 872 | mci->csrows[i].mtype = MEM_RDDR2; |
@@ -777,7 +878,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) | |||
777 | mci->csrows[i].channels[0].csrow = mci->csrows + i; | 878 | mci->csrows[i].channels[0].csrow = mci->csrows + i; |
778 | snprintf(mci->csrows[i].channels[0].label, | 879 | snprintf(mci->csrows[i].channels[0].label, |
779 | sizeof(mci->csrows[i].channels[0].label), | 880 | sizeof(mci->csrows[i].channels[0].label), |
780 | "DIMM%u", i5100_rank_to_slot(mci, cntlr, rank)); | 881 | "DIMM%u", i5100_rank_to_slot(mci, chan, rank)); |
781 | 882 | ||
782 | total_pages += npages; | 883 | total_pages += npages; |
783 | } | 884 | } |
@@ -815,13 +916,6 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, | |||
815 | pci_read_config_dword(pdev, I5100_MS, &dw); | 916 | pci_read_config_dword(pdev, I5100_MS, &dw); |
816 | ranksperch = !!(dw & (1 << 8)) * 2 + 4; | 917 | ranksperch = !!(dw & (1 << 8)) * 2 + 4; |
817 | 918 | ||
818 | if (ranksperch != 4) { | ||
819 | /* FIXME: get 6 ranks / controller to work - need hw... */ | ||
820 | printk(KERN_INFO "i5100_edac: unsupported configuration.\n"); | ||
821 | ret = -ENODEV; | ||
822 | goto bail_pdev; | ||
823 | } | ||
824 | |||
825 | /* enable error reporting... */ | 919 | /* enable error reporting... */ |
826 | pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw); | 920 | pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw); |
827 | dw &= ~I5100_FERR_NF_MEM_ANY_MASK; | 921 | dw &= ~I5100_FERR_NF_MEM_ANY_MASK; |
@@ -864,11 +958,21 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, | |||
864 | mci->dev = &pdev->dev; | 958 | mci->dev = &pdev->dev; |
865 | 959 | ||
866 | priv = mci->pvt_info; | 960 | priv = mci->pvt_info; |
867 | priv->ranksperctlr = ranksperch; | 961 | priv->ranksperchan = ranksperch; |
868 | priv->mc = pdev; | 962 | priv->mc = pdev; |
869 | priv->ch0mm = ch0mm; | 963 | priv->ch0mm = ch0mm; |
870 | priv->ch1mm = ch1mm; | 964 | priv->ch1mm = ch1mm; |
871 | 965 | ||
966 | INIT_DELAYED_WORK(&(priv->i5100_scrubbing), i5100_refresh_scrubbing); | ||
967 | |||
968 | /* If scrubbing was already enabled by the bios, start maintaining it */ | ||
969 | pci_read_config_dword(pdev, I5100_MC, &dw); | ||
970 | if (i5100_mc_scrben(dw)) { | ||
971 | priv->scrub_enable = 1; | ||
972 | schedule_delayed_work(&(priv->i5100_scrubbing), | ||
973 | I5100_SCRUB_REFRESH_RATE); | ||
974 | } | ||
975 | |||
872 | i5100_init_dimm_layout(pdev, mci); | 976 | i5100_init_dimm_layout(pdev, mci); |
873 | i5100_init_interleaving(pdev, mci); | 977 | i5100_init_interleaving(pdev, mci); |
874 | 978 | ||
@@ -882,6 +986,8 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, | |||
882 | mci->ctl_page_to_phys = NULL; | 986 | mci->ctl_page_to_phys = NULL; |
883 | 987 | ||
884 | mci->edac_check = i5100_check_error; | 988 | mci->edac_check = i5100_check_error; |
989 | mci->set_sdram_scrub_rate = i5100_set_scrub_rate; | ||
990 | mci->get_sdram_scrub_rate = i5100_get_scrub_rate; | ||
885 | 991 | ||
886 | i5100_init_csrows(mci); | 992 | i5100_init_csrows(mci); |
887 | 993 | ||
@@ -897,12 +1003,14 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, | |||
897 | 1003 | ||
898 | if (edac_mc_add_mc(mci)) { | 1004 | if (edac_mc_add_mc(mci)) { |
899 | ret = -ENODEV; | 1005 | ret = -ENODEV; |
900 | goto bail_mc; | 1006 | goto bail_scrub; |
901 | } | 1007 | } |
902 | 1008 | ||
903 | return ret; | 1009 | return ret; |
904 | 1010 | ||
905 | bail_mc: | 1011 | bail_scrub: |
1012 | priv->scrub_enable = 0; | ||
1013 | cancel_delayed_work_sync(&(priv->i5100_scrubbing)); | ||
906 | edac_mc_free(mci); | 1014 | edac_mc_free(mci); |
907 | 1015 | ||
908 | bail_disable_ch1: | 1016 | bail_disable_ch1: |
@@ -935,6 +1043,10 @@ static void __devexit i5100_remove_one(struct pci_dev *pdev) | |||
935 | return; | 1043 | return; |
936 | 1044 | ||
937 | priv = mci->pvt_info; | 1045 | priv = mci->pvt_info; |
1046 | |||
1047 | priv->scrub_enable = 0; | ||
1048 | cancel_delayed_work_sync(&(priv->i5100_scrubbing)); | ||
1049 | |||
938 | pci_disable_device(pdev); | 1050 | pci_disable_device(pdev); |
939 | pci_disable_device(priv->ch0mm); | 1051 | pci_disable_device(priv->ch0mm); |
940 | pci_disable_device(priv->ch1mm); | 1052 | pci_disable_device(priv->ch1mm); |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 57ca339924ef..a019b49ecc9b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -206,6 +206,12 @@ config GPIO_LANGWELL | |||
206 | help | 206 | help |
207 | Say Y here to support Intel Moorestown platform GPIO. | 207 | Say Y here to support Intel Moorestown platform GPIO. |
208 | 208 | ||
209 | config GPIO_TIMBERDALE | ||
210 | bool "Support for timberdale GPIO IP" | ||
211 | depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM | ||
212 | ---help--- | ||
213 | Add support for the GPIO IP in the timberdale FPGA. | ||
214 | |||
209 | comment "SPI GPIO expanders:" | 215 | comment "SPI GPIO expanders:" |
210 | 216 | ||
211 | config GPIO_MAX7301 | 217 | config GPIO_MAX7301 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 270b6d7839f5..52fe4cf734c7 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o | |||
13 | obj-$(CONFIG_GPIO_PCA953X) += pca953x.o | 13 | obj-$(CONFIG_GPIO_PCA953X) += pca953x.o |
14 | obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o | 14 | obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o |
15 | obj-$(CONFIG_GPIO_PL061) += pl061.o | 15 | obj-$(CONFIG_GPIO_PL061) += pl061.o |
16 | obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o | ||
16 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o | 17 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o |
17 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o | 18 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o |
18 | obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o | 19 | obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o |
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50de0f5750d8..a25ad284a272 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -53,6 +53,7 @@ struct gpio_desc { | |||
53 | #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ | 53 | #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ |
54 | #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ | 54 | #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ |
55 | #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ | 55 | #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ |
56 | #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ | ||
56 | 57 | ||
57 | #define PDESC_ID_SHIFT 16 /* add new flags before this one */ | 58 | #define PDESC_ID_SHIFT 16 /* add new flags before this one */ |
58 | 59 | ||
@@ -210,6 +211,11 @@ static DEFINE_MUTEX(sysfs_lock); | |||
210 | * * configures behavior of poll(2) on /value | 211 | * * configures behavior of poll(2) on /value |
211 | * * available only if pin can generate IRQs on input | 212 | * * available only if pin can generate IRQs on input |
212 | * * is read/write as "none", "falling", "rising", or "both" | 213 | * * is read/write as "none", "falling", "rising", or "both" |
214 | * /active_low | ||
215 | * * configures polarity of /value | ||
216 | * * is read/write as zero/nonzero | ||
217 | * * also affects existing and subsequent "falling" and "rising" | ||
218 | * /edge configuration | ||
213 | */ | 219 | */ |
214 | 220 | ||
215 | static ssize_t gpio_direction_show(struct device *dev, | 221 | static ssize_t gpio_direction_show(struct device *dev, |
@@ -255,7 +261,7 @@ static ssize_t gpio_direction_store(struct device *dev, | |||
255 | return status ? : size; | 261 | return status ? : size; |
256 | } | 262 | } |
257 | 263 | ||
258 | static const DEVICE_ATTR(direction, 0644, | 264 | static /* const */ DEVICE_ATTR(direction, 0644, |
259 | gpio_direction_show, gpio_direction_store); | 265 | gpio_direction_show, gpio_direction_store); |
260 | 266 | ||
261 | static ssize_t gpio_value_show(struct device *dev, | 267 | static ssize_t gpio_value_show(struct device *dev, |
@@ -267,10 +273,17 @@ static ssize_t gpio_value_show(struct device *dev, | |||
267 | 273 | ||
268 | mutex_lock(&sysfs_lock); | 274 | mutex_lock(&sysfs_lock); |
269 | 275 | ||
270 | if (!test_bit(FLAG_EXPORT, &desc->flags)) | 276 | if (!test_bit(FLAG_EXPORT, &desc->flags)) { |
271 | status = -EIO; | 277 | status = -EIO; |
272 | else | 278 | } else { |
273 | status = sprintf(buf, "%d\n", !!gpio_get_value_cansleep(gpio)); | 279 | int value; |
280 | |||
281 | value = !!gpio_get_value_cansleep(gpio); | ||
282 | if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) | ||
283 | value = !value; | ||
284 | |||
285 | status = sprintf(buf, "%d\n", value); | ||
286 | } | ||
274 | 287 | ||
275 | mutex_unlock(&sysfs_lock); | 288 | mutex_unlock(&sysfs_lock); |
276 | return status; | 289 | return status; |
@@ -294,6 +307,8 @@ static ssize_t gpio_value_store(struct device *dev, | |||
294 | 307 | ||
295 | status = strict_strtol(buf, 0, &value); | 308 | status = strict_strtol(buf, 0, &value); |
296 | if (status == 0) { | 309 | if (status == 0) { |
310 | if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) | ||
311 | value = !value; | ||
297 | gpio_set_value_cansleep(gpio, value != 0); | 312 | gpio_set_value_cansleep(gpio, value != 0); |
298 | status = size; | 313 | status = size; |
299 | } | 314 | } |
@@ -303,7 +318,7 @@ static ssize_t gpio_value_store(struct device *dev, | |||
303 | return status; | 318 | return status; |
304 | } | 319 | } |
305 | 320 | ||
306 | static /*const*/ DEVICE_ATTR(value, 0644, | 321 | static const DEVICE_ATTR(value, 0644, |
307 | gpio_value_show, gpio_value_store); | 322 | gpio_value_show, gpio_value_store); |
308 | 323 | ||
309 | static irqreturn_t gpio_sysfs_irq(int irq, void *priv) | 324 | static irqreturn_t gpio_sysfs_irq(int irq, void *priv) |
@@ -352,9 +367,11 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, | |||
352 | 367 | ||
353 | irq_flags = IRQF_SHARED; | 368 | irq_flags = IRQF_SHARED; |
354 | if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) | 369 | if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) |
355 | irq_flags |= IRQF_TRIGGER_FALLING; | 370 | irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? |
371 | IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; | ||
356 | if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) | 372 | if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) |
357 | irq_flags |= IRQF_TRIGGER_RISING; | 373 | irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? |
374 | IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; | ||
358 | 375 | ||
359 | if (!pdesc) { | 376 | if (!pdesc) { |
360 | pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL); | 377 | pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL); |
@@ -475,9 +492,79 @@ found: | |||
475 | 492 | ||
476 | static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); | 493 | static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); |
477 | 494 | ||
495 | static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, | ||
496 | int value) | ||
497 | { | ||
498 | int status = 0; | ||
499 | |||
500 | if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) | ||
501 | return 0; | ||
502 | |||
503 | if (value) | ||
504 | set_bit(FLAG_ACTIVE_LOW, &desc->flags); | ||
505 | else | ||
506 | clear_bit(FLAG_ACTIVE_LOW, &desc->flags); | ||
507 | |||
508 | /* reconfigure poll(2) support if enabled on one edge only */ | ||
509 | if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^ | ||
510 | !!test_bit(FLAG_TRIG_FALL, &desc->flags))) { | ||
511 | unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; | ||
512 | |||
513 | gpio_setup_irq(desc, dev, 0); | ||
514 | status = gpio_setup_irq(desc, dev, trigger_flags); | ||
515 | } | ||
516 | |||
517 | return status; | ||
518 | } | ||
519 | |||
520 | static ssize_t gpio_active_low_show(struct device *dev, | ||
521 | struct device_attribute *attr, char *buf) | ||
522 | { | ||
523 | const struct gpio_desc *desc = dev_get_drvdata(dev); | ||
524 | ssize_t status; | ||
525 | |||
526 | mutex_lock(&sysfs_lock); | ||
527 | |||
528 | if (!test_bit(FLAG_EXPORT, &desc->flags)) | ||
529 | status = -EIO; | ||
530 | else | ||
531 | status = sprintf(buf, "%d\n", | ||
532 | !!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); | ||
533 | |||
534 | mutex_unlock(&sysfs_lock); | ||
535 | |||
536 | return status; | ||
537 | } | ||
538 | |||
539 | static ssize_t gpio_active_low_store(struct device *dev, | ||
540 | struct device_attribute *attr, const char *buf, size_t size) | ||
541 | { | ||
542 | struct gpio_desc *desc = dev_get_drvdata(dev); | ||
543 | ssize_t status; | ||
544 | |||
545 | mutex_lock(&sysfs_lock); | ||
546 | |||
547 | if (!test_bit(FLAG_EXPORT, &desc->flags)) { | ||
548 | status = -EIO; | ||
549 | } else { | ||
550 | long value; | ||
551 | |||
552 | status = strict_strtol(buf, 0, &value); | ||
553 | if (status == 0) | ||
554 | status = sysfs_set_active_low(desc, dev, value != 0); | ||
555 | } | ||
556 | |||
557 | mutex_unlock(&sysfs_lock); | ||
558 | |||
559 | return status ? : size; | ||
560 | } | ||
561 | |||
562 | static const DEVICE_ATTR(active_low, 0644, | ||
563 | gpio_active_low_show, gpio_active_low_store); | ||
564 | |||
478 | static const struct attribute *gpio_attrs[] = { | 565 | static const struct attribute *gpio_attrs[] = { |
479 | &dev_attr_direction.attr, | ||
480 | &dev_attr_value.attr, | 566 | &dev_attr_value.attr, |
567 | &dev_attr_active_low.attr, | ||
481 | NULL, | 568 | NULL, |
482 | }; | 569 | }; |
483 | 570 | ||
@@ -662,12 +749,12 @@ int gpio_export(unsigned gpio, bool direction_may_change) | |||
662 | dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), | 749 | dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), |
663 | desc, ioname ? ioname : "gpio%d", gpio); | 750 | desc, ioname ? ioname : "gpio%d", gpio); |
664 | if (!IS_ERR(dev)) { | 751 | if (!IS_ERR(dev)) { |
665 | if (direction_may_change) | 752 | status = sysfs_create_group(&dev->kobj, |
666 | status = sysfs_create_group(&dev->kobj, | ||
667 | &gpio_attr_group); | 753 | &gpio_attr_group); |
668 | else | 754 | |
755 | if (!status && direction_may_change) | ||
669 | status = device_create_file(dev, | 756 | status = device_create_file(dev, |
670 | &dev_attr_value); | 757 | &dev_attr_direction); |
671 | 758 | ||
672 | if (!status && gpio_to_irq(gpio) >= 0 | 759 | if (!status && gpio_to_irq(gpio) >= 0 |
673 | && (direction_may_change | 760 | && (direction_may_change |
@@ -744,6 +831,55 @@ done: | |||
744 | } | 831 | } |
745 | EXPORT_SYMBOL_GPL(gpio_export_link); | 832 | EXPORT_SYMBOL_GPL(gpio_export_link); |
746 | 833 | ||
834 | |||
835 | /** | ||
836 | * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value | ||
837 | * @gpio: gpio to change | ||
838 | * @value: non-zero to use active low, i.e. inverted values | ||
839 | * | ||
840 | * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute. | ||
841 | * The GPIO does not have to be exported yet. If poll(2) support has | ||
842 | * been enabled for either rising or falling edge, it will be | ||
843 | * reconfigured to follow the new polarity. | ||
844 | * | ||
845 | * Returns zero on success, else an error. | ||
846 | */ | ||
847 | int gpio_sysfs_set_active_low(unsigned gpio, int value) | ||
848 | { | ||
849 | struct gpio_desc *desc; | ||
850 | struct device *dev = NULL; | ||
851 | int status = -EINVAL; | ||
852 | |||
853 | if (!gpio_is_valid(gpio)) | ||
854 | goto done; | ||
855 | |||
856 | mutex_lock(&sysfs_lock); | ||
857 | |||
858 | desc = &gpio_desc[gpio]; | ||
859 | |||
860 | if (test_bit(FLAG_EXPORT, &desc->flags)) { | ||
861 | struct device *dev; | ||
862 | |||
863 | dev = class_find_device(&gpio_class, NULL, desc, match_export); | ||
864 | if (dev == NULL) { | ||
865 | status = -ENODEV; | ||
866 | goto unlock; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | status = sysfs_set_active_low(desc, dev, value); | ||
871 | |||
872 | unlock: | ||
873 | mutex_unlock(&sysfs_lock); | ||
874 | |||
875 | done: | ||
876 | if (status) | ||
877 | pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); | ||
878 | |||
879 | return status; | ||
880 | } | ||
881 | EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); | ||
882 | |||
747 | /** | 883 | /** |
748 | * gpio_unexport - reverse effect of gpio_export() | 884 | * gpio_unexport - reverse effect of gpio_export() |
749 | * @gpio: gpio to make unavailable | 885 | * @gpio: gpio to make unavailable |
@@ -1094,6 +1230,7 @@ void gpio_free(unsigned gpio) | |||
1094 | } | 1230 | } |
1095 | desc_set_label(desc, NULL); | 1231 | desc_set_label(desc, NULL); |
1096 | module_put(desc->chip->owner); | 1232 | module_put(desc->chip->owner); |
1233 | clear_bit(FLAG_ACTIVE_LOW, &desc->flags); | ||
1097 | clear_bit(FLAG_REQUESTED, &desc->flags); | 1234 | clear_bit(FLAG_REQUESTED, &desc->flags); |
1098 | } else | 1235 | } else |
1099 | WARN_ON(extra_checks); | 1236 | WARN_ON(extra_checks); |
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 4baf3d7d0f8e..6c0ebbdc659e 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c | |||
@@ -123,7 +123,7 @@ static int lnw_irq_type(unsigned irq, unsigned type) | |||
123 | void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]); | 123 | void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]); |
124 | void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]); | 124 | void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]); |
125 | 125 | ||
126 | if (gpio < 0 || gpio > lnw->chip.ngpio) | 126 | if (gpio >= lnw->chip.ngpio) |
127 | return -EINVAL; | 127 | return -EINVAL; |
128 | spin_lock_irqsave(&lnw->lock, flags); | 128 | spin_lock_irqsave(&lnw->lock, flags); |
129 | if (type & IRQ_TYPE_EDGE_RISING) | 129 | if (type & IRQ_TYPE_EDGE_RISING) |
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c new file mode 100644 index 000000000000..a4d344ba8e5c --- /dev/null +++ b/drivers/gpio/timbgpio.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * timbgpio.c timberdale FPGA GPIO driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA GPIO | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/timb_gpio.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | |||
30 | #define DRIVER_NAME "timb-gpio" | ||
31 | |||
32 | #define TGPIOVAL 0x00 | ||
33 | #define TGPIODIR 0x04 | ||
34 | #define TGPIO_IER 0x08 | ||
35 | #define TGPIO_ISR 0x0c | ||
36 | #define TGPIO_IPR 0x10 | ||
37 | #define TGPIO_ICR 0x14 | ||
38 | #define TGPIO_FLR 0x18 | ||
39 | #define TGPIO_LVR 0x1c | ||
40 | |||
41 | struct timbgpio { | ||
42 | void __iomem *membase; | ||
43 | spinlock_t lock; /* mutual exclusion */ | ||
44 | struct gpio_chip gpio; | ||
45 | int irq_base; | ||
46 | }; | ||
47 | |||
48 | static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, | ||
49 | unsigned offset, bool enabled) | ||
50 | { | ||
51 | struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); | ||
52 | u32 reg; | ||
53 | |||
54 | spin_lock(&tgpio->lock); | ||
55 | reg = ioread32(tgpio->membase + offset); | ||
56 | |||
57 | if (enabled) | ||
58 | reg |= (1 << index); | ||
59 | else | ||
60 | reg &= ~(1 << index); | ||
61 | |||
62 | iowrite32(reg, tgpio->membase + offset); | ||
63 | spin_unlock(&tgpio->lock); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) | ||
69 | { | ||
70 | return timbgpio_update_bit(gpio, nr, TGPIODIR, true); | ||
71 | } | ||
72 | |||
73 | static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr) | ||
74 | { | ||
75 | struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); | ||
76 | u32 value; | ||
77 | |||
78 | value = ioread32(tgpio->membase + TGPIOVAL); | ||
79 | return (value & (1 << nr)) ? 1 : 0; | ||
80 | } | ||
81 | |||
82 | static int timbgpio_gpio_direction_output(struct gpio_chip *gpio, | ||
83 | unsigned nr, int val) | ||
84 | { | ||
85 | return timbgpio_update_bit(gpio, nr, TGPIODIR, false); | ||
86 | } | ||
87 | |||
88 | static void timbgpio_gpio_set(struct gpio_chip *gpio, | ||
89 | unsigned nr, int val) | ||
90 | { | ||
91 | timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0); | ||
92 | } | ||
93 | |||
94 | static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset) | ||
95 | { | ||
96 | struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); | ||
97 | |||
98 | if (tgpio->irq_base <= 0) | ||
99 | return -EINVAL; | ||
100 | |||
101 | return tgpio->irq_base + offset; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * GPIO IRQ | ||
106 | */ | ||
107 | static void timbgpio_irq_disable(unsigned irq) | ||
108 | { | ||
109 | struct timbgpio *tgpio = get_irq_chip_data(irq); | ||
110 | int offset = irq - tgpio->irq_base; | ||
111 | |||
112 | timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0); | ||
113 | } | ||
114 | |||
115 | static void timbgpio_irq_enable(unsigned irq) | ||
116 | { | ||
117 | struct timbgpio *tgpio = get_irq_chip_data(irq); | ||
118 | int offset = irq - tgpio->irq_base; | ||
119 | |||
120 | timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1); | ||
121 | } | ||
122 | |||
123 | static int timbgpio_irq_type(unsigned irq, unsigned trigger) | ||
124 | { | ||
125 | struct timbgpio *tgpio = get_irq_chip_data(irq); | ||
126 | int offset = irq - tgpio->irq_base; | ||
127 | unsigned long flags; | ||
128 | u32 lvr, flr; | ||
129 | |||
130 | if (offset < 0 || offset > tgpio->gpio.ngpio) | ||
131 | return -EINVAL; | ||
132 | |||
133 | spin_lock_irqsave(&tgpio->lock, flags); | ||
134 | |||
135 | lvr = ioread32(tgpio->membase + TGPIO_LVR); | ||
136 | flr = ioread32(tgpio->membase + TGPIO_FLR); | ||
137 | |||
138 | if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { | ||
139 | flr &= ~(1 << offset); | ||
140 | if (trigger & IRQ_TYPE_LEVEL_HIGH) | ||
141 | lvr |= 1 << offset; | ||
142 | else | ||
143 | lvr &= ~(1 << offset); | ||
144 | } | ||
145 | |||
146 | if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) | ||
147 | return -EINVAL; | ||
148 | else { | ||
149 | flr |= 1 << offset; | ||
150 | /* opposite compared to the datasheet, but it mirrors the | ||
151 | * reality | ||
152 | */ | ||
153 | if (trigger & IRQ_TYPE_EDGE_FALLING) | ||
154 | lvr |= 1 << offset; | ||
155 | else | ||
156 | lvr &= ~(1 << offset); | ||
157 | } | ||
158 | |||
159 | iowrite32(lvr, tgpio->membase + TGPIO_LVR); | ||
160 | iowrite32(flr, tgpio->membase + TGPIO_FLR); | ||
161 | iowrite32(1 << offset, tgpio->membase + TGPIO_ICR); | ||
162 | spin_unlock_irqrestore(&tgpio->lock, flags); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) | ||
168 | { | ||
169 | struct timbgpio *tgpio = get_irq_data(irq); | ||
170 | unsigned long ipr; | ||
171 | int offset; | ||
172 | |||
173 | desc->chip->ack(irq); | ||
174 | ipr = ioread32(tgpio->membase + TGPIO_IPR); | ||
175 | iowrite32(ipr, tgpio->membase + TGPIO_ICR); | ||
176 | |||
177 | for_each_bit(offset, &ipr, tgpio->gpio.ngpio) | ||
178 | generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); | ||
179 | } | ||
180 | |||
181 | static struct irq_chip timbgpio_irqchip = { | ||
182 | .name = "GPIO", | ||
183 | .enable = timbgpio_irq_enable, | ||
184 | .disable = timbgpio_irq_disable, | ||
185 | .set_type = timbgpio_irq_type, | ||
186 | }; | ||
187 | |||
188 | static int __devinit timbgpio_probe(struct platform_device *pdev) | ||
189 | { | ||
190 | int err, i; | ||
191 | struct gpio_chip *gc; | ||
192 | struct timbgpio *tgpio; | ||
193 | struct resource *iomem; | ||
194 | struct timbgpio_platform_data *pdata = pdev->dev.platform_data; | ||
195 | int irq = platform_get_irq(pdev, 0); | ||
196 | |||
197 | if (!pdata || pdata->nr_pins > 32) { | ||
198 | err = -EINVAL; | ||
199 | goto err_mem; | ||
200 | } | ||
201 | |||
202 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
203 | if (!iomem) { | ||
204 | err = -EINVAL; | ||
205 | goto err_mem; | ||
206 | } | ||
207 | |||
208 | tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL); | ||
209 | if (!tgpio) { | ||
210 | err = -EINVAL; | ||
211 | goto err_mem; | ||
212 | } | ||
213 | tgpio->irq_base = pdata->irq_base; | ||
214 | |||
215 | spin_lock_init(&tgpio->lock); | ||
216 | |||
217 | if (!request_mem_region(iomem->start, resource_size(iomem), | ||
218 | DRIVER_NAME)) { | ||
219 | err = -EBUSY; | ||
220 | goto err_request; | ||
221 | } | ||
222 | |||
223 | tgpio->membase = ioremap(iomem->start, resource_size(iomem)); | ||
224 | if (!tgpio->membase) { | ||
225 | err = -ENOMEM; | ||
226 | goto err_ioremap; | ||
227 | } | ||
228 | |||
229 | gc = &tgpio->gpio; | ||
230 | |||
231 | gc->label = dev_name(&pdev->dev); | ||
232 | gc->owner = THIS_MODULE; | ||
233 | gc->dev = &pdev->dev; | ||
234 | gc->direction_input = timbgpio_gpio_direction_input; | ||
235 | gc->get = timbgpio_gpio_get; | ||
236 | gc->direction_output = timbgpio_gpio_direction_output; | ||
237 | gc->set = timbgpio_gpio_set; | ||
238 | gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL; | ||
239 | gc->dbg_show = NULL; | ||
240 | gc->base = pdata->gpio_base; | ||
241 | gc->ngpio = pdata->nr_pins; | ||
242 | gc->can_sleep = 0; | ||
243 | |||
244 | err = gpiochip_add(gc); | ||
245 | if (err) | ||
246 | goto err_chipadd; | ||
247 | |||
248 | platform_set_drvdata(pdev, tgpio); | ||
249 | |||
250 | /* make sure to disable interrupts */ | ||
251 | iowrite32(0x0, tgpio->membase + TGPIO_IER); | ||
252 | |||
253 | if (irq < 0 || tgpio->irq_base <= 0) | ||
254 | return 0; | ||
255 | |||
256 | for (i = 0; i < pdata->nr_pins; i++) { | ||
257 | set_irq_chip_and_handler_name(tgpio->irq_base + i, | ||
258 | &timbgpio_irqchip, handle_simple_irq, "mux"); | ||
259 | set_irq_chip_data(tgpio->irq_base + i, tgpio); | ||
260 | #ifdef CONFIG_ARM | ||
261 | set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | set_irq_data(irq, tgpio); | ||
266 | set_irq_chained_handler(irq, timbgpio_irq); | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | err_chipadd: | ||
271 | iounmap(tgpio->membase); | ||
272 | err_ioremap: | ||
273 | release_mem_region(iomem->start, resource_size(iomem)); | ||
274 | err_request: | ||
275 | kfree(tgpio); | ||
276 | err_mem: | ||
277 | printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err); | ||
278 | |||
279 | return err; | ||
280 | } | ||
281 | |||
282 | static int __devexit timbgpio_remove(struct platform_device *pdev) | ||
283 | { | ||
284 | int err; | ||
285 | struct timbgpio_platform_data *pdata = pdev->dev.platform_data; | ||
286 | struct timbgpio *tgpio = platform_get_drvdata(pdev); | ||
287 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
288 | int irq = platform_get_irq(pdev, 0); | ||
289 | |||
290 | if (irq >= 0 && tgpio->irq_base > 0) { | ||
291 | int i; | ||
292 | for (i = 0; i < pdata->nr_pins; i++) { | ||
293 | set_irq_chip(tgpio->irq_base + i, NULL); | ||
294 | set_irq_chip_data(tgpio->irq_base + i, NULL); | ||
295 | } | ||
296 | |||
297 | set_irq_handler(irq, NULL); | ||
298 | set_irq_data(irq, NULL); | ||
299 | } | ||
300 | |||
301 | err = gpiochip_remove(&tgpio->gpio); | ||
302 | if (err) | ||
303 | printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); | ||
304 | |||
305 | iounmap(tgpio->membase); | ||
306 | release_mem_region(iomem->start, resource_size(iomem)); | ||
307 | kfree(tgpio); | ||
308 | |||
309 | platform_set_drvdata(pdev, NULL); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static struct platform_driver timbgpio_platform_driver = { | ||
315 | .driver = { | ||
316 | .name = DRIVER_NAME, | ||
317 | .owner = THIS_MODULE, | ||
318 | }, | ||
319 | .probe = timbgpio_probe, | ||
320 | .remove = timbgpio_remove, | ||
321 | }; | ||
322 | |||
323 | /*--------------------------------------------------------------------------*/ | ||
324 | |||
325 | static int __init timbgpio_init(void) | ||
326 | { | ||
327 | return platform_driver_register(&timbgpio_platform_driver); | ||
328 | } | ||
329 | |||
330 | static void __exit timbgpio_exit(void) | ||
331 | { | ||
332 | platform_driver_unregister(&timbgpio_platform_driver); | ||
333 | } | ||
334 | |||
335 | module_init(timbgpio_init); | ||
336 | module_exit(timbgpio_exit); | ||
337 | |||
338 | MODULE_DESCRIPTION("Timberdale GPIO driver"); | ||
339 | MODULE_LICENSE("GPL v2"); | ||
340 | MODULE_AUTHOR("Mocean Laboratories"); | ||
341 | MODULE_ALIAS("platform:"DRIVER_NAME); | ||
342 | |||
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig new file mode 100644 index 000000000000..4dde7d180a32 --- /dev/null +++ b/drivers/media/IR/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config IR_CORE | ||
2 | tristate | ||
3 | depends on INPUT | ||
4 | default INPUT | ||
5 | |||
6 | config VIDEO_IR | ||
7 | tristate | ||
8 | depends on IR_CORE | ||
9 | default IR_CORE | ||
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile new file mode 100644 index 000000000000..df5ddb4bbbf7 --- /dev/null +++ b/drivers/media/IR/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | ir-common-objs := ir-functions.o ir-keymaps.o | ||
2 | ir-core-objs := ir-keytable.o | ||
3 | |||
4 | obj-$(CONFIG_IR_CORE) += ir-core.o | ||
5 | obj-$(CONFIG_VIDEO_IR) += ir-common.o | ||
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/IR/ir-functions.c index e616f624ceaa..776a136616d6 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/IR/ir-functions.c | |||
@@ -34,9 +34,6 @@ static int repeat = 1; | |||
34 | module_param(repeat, int, 0444); | 34 | module_param(repeat, int, 0444); |
35 | MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)"); | 35 | MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)"); |
36 | 36 | ||
37 | int media_ir_debug; /* media_ir_debug level (0,1,2) */ | ||
38 | module_param_named(debug, media_ir_debug, int, 0644); | ||
39 | |||
40 | /* -------------------------------------------------------------------------- */ | 37 | /* -------------------------------------------------------------------------- */ |
41 | 38 | ||
42 | static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) | 39 | static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) |
@@ -55,25 +52,10 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) | |||
55 | /* -------------------------------------------------------------------------- */ | 52 | /* -------------------------------------------------------------------------- */ |
56 | 53 | ||
57 | int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, | 54 | int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, |
58 | int ir_type, struct ir_scancode_table *ir_codes) | 55 | int ir_type) |
59 | { | 56 | { |
60 | ir->ir_type = ir_type; | 57 | ir->ir_type = ir_type; |
61 | 58 | ||
62 | ir->keytable.size = ir_roundup_tablesize(ir_codes->size); | ||
63 | ir->keytable.scan = kzalloc(ir->keytable.size * | ||
64 | sizeof(struct ir_scancode), GFP_KERNEL); | ||
65 | if (!ir->keytable.scan) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", | ||
69 | ir->keytable.size, | ||
70 | ir->keytable.size * sizeof(ir->keytable.scan)); | ||
71 | |||
72 | ir_copy_table(&ir->keytable, ir_codes); | ||
73 | ir_set_keycode_table(dev, &ir->keytable); | ||
74 | |||
75 | clear_bit(0, dev->keybit); | ||
76 | set_bit(EV_KEY, dev->evbit); | ||
77 | if (repeat) | 59 | if (repeat) |
78 | set_bit(EV_REP, dev->evbit); | 60 | set_bit(EV_REP, dev->evbit); |
79 | 61 | ||
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/IR/ir-keymaps.c index 328c973a0838..9bbe6b1e9871 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/IR/ir-keymaps.c | |||
@@ -1847,76 +1847,6 @@ struct ir_scancode_table ir_codes_hauppauge_new_table = { | |||
1847 | }; | 1847 | }; |
1848 | EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table); | 1848 | EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table); |
1849 | 1849 | ||
1850 | /* | ||
1851 | * Hauppauge:the newer, gray remotes (seems there are multiple | ||
1852 | * slightly different versions), shipped with cx88+ivtv cards. | ||
1853 | * | ||
1854 | * This table contains the complete RC5 code, instead of just the data part | ||
1855 | */ | ||
1856 | static struct ir_scancode ir_codes_rc5_hauppauge_new[] = { | ||
1857 | /* Keys 0 to 9 */ | ||
1858 | { 0x1e00, KEY_0 }, | ||
1859 | { 0x1e01, KEY_1 }, | ||
1860 | { 0x1e02, KEY_2 }, | ||
1861 | { 0x1e03, KEY_3 }, | ||
1862 | { 0x1e04, KEY_4 }, | ||
1863 | { 0x1e05, KEY_5 }, | ||
1864 | { 0x1e06, KEY_6 }, | ||
1865 | { 0x1e07, KEY_7 }, | ||
1866 | { 0x1e08, KEY_8 }, | ||
1867 | { 0x1e09, KEY_9 }, | ||
1868 | |||
1869 | { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ | ||
1870 | { 0x1e0b, KEY_RED }, /* red button */ | ||
1871 | { 0x1e0c, KEY_RADIO }, | ||
1872 | { 0x1e0d, KEY_MENU }, | ||
1873 | { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ | ||
1874 | { 0x1e0f, KEY_MUTE }, | ||
1875 | { 0x1e10, KEY_VOLUMEUP }, | ||
1876 | { 0x1e11, KEY_VOLUMEDOWN }, | ||
1877 | { 0x1e12, KEY_PREVIOUS }, /* previous channel */ | ||
1878 | { 0x1e14, KEY_UP }, | ||
1879 | { 0x1e15, KEY_DOWN }, | ||
1880 | { 0x1e16, KEY_LEFT }, | ||
1881 | { 0x1e17, KEY_RIGHT }, | ||
1882 | { 0x1e18, KEY_VIDEO }, /* Videos */ | ||
1883 | { 0x1e19, KEY_AUDIO }, /* Music */ | ||
1884 | /* 0x1e1a: Pictures - presume this means | ||
1885 | "Multimedia Home Platform" - | ||
1886 | no "PICTURES" key in input.h | ||
1887 | */ | ||
1888 | { 0x1e1a, KEY_MHP }, | ||
1889 | |||
1890 | { 0x1e1b, KEY_EPG }, /* Guide */ | ||
1891 | { 0x1e1c, KEY_TV }, | ||
1892 | { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ | ||
1893 | { 0x1e1f, KEY_EXIT }, /* back/exit */ | ||
1894 | { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ | ||
1895 | { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ | ||
1896 | { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ | ||
1897 | { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ | ||
1898 | { 0x1e25, KEY_ENTER }, /* OK */ | ||
1899 | { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ | ||
1900 | { 0x1e29, KEY_BLUE }, /* blue key */ | ||
1901 | { 0x1e2e, KEY_GREEN }, /* green button */ | ||
1902 | { 0x1e30, KEY_PAUSE }, /* pause */ | ||
1903 | { 0x1e32, KEY_REWIND }, /* backward << */ | ||
1904 | { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ | ||
1905 | { 0x1e35, KEY_PLAY }, | ||
1906 | { 0x1e36, KEY_STOP }, | ||
1907 | { 0x1e37, KEY_RECORD }, /* recording */ | ||
1908 | { 0x1e38, KEY_YELLOW }, /* yellow key */ | ||
1909 | { 0x1e3b, KEY_SELECT }, /* top right button */ | ||
1910 | { 0x1e3c, KEY_ZOOM }, /* full */ | ||
1911 | { 0x1e3d, KEY_POWER }, /* system power (green button) */ | ||
1912 | }; | ||
1913 | |||
1914 | struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = { | ||
1915 | .scan = ir_codes_rc5_hauppauge_new, | ||
1916 | .size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new), | ||
1917 | }; | ||
1918 | EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table); | ||
1919 | |||
1920 | static struct ir_scancode ir_codes_npgtech[] = { | 1850 | static struct ir_scancode ir_codes_npgtech[] = { |
1921 | { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ | 1851 | { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ |
1922 | { 0x2a, KEY_FRONT }, | 1852 | { 0x2a, KEY_FRONT }, |
@@ -3314,3 +3244,152 @@ struct ir_scancode_table ir_codes_gadmei_rm008z_table = { | |||
3314 | }; | 3244 | }; |
3315 | EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table); | 3245 | EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table); |
3316 | 3246 | ||
3247 | /************************************************************* | ||
3248 | * COMPLETE SCANCODE TABLES | ||
3249 | * Instead of just a partial scancode, the tables bellow | ||
3250 | * contains the complete scancode and the receiver protocol | ||
3251 | *************************************************************/ | ||
3252 | |||
3253 | /* | ||
3254 | * Hauppauge:the newer, gray remotes (seems there are multiple | ||
3255 | * slightly different versions), shipped with cx88+ivtv cards. | ||
3256 | * | ||
3257 | * This table contains the complete RC5 code, instead of just the data part | ||
3258 | */ | ||
3259 | static struct ir_scancode ir_codes_rc5_hauppauge_new[] = { | ||
3260 | /* Keys 0 to 9 */ | ||
3261 | { 0x1e00, KEY_0 }, | ||
3262 | { 0x1e01, KEY_1 }, | ||
3263 | { 0x1e02, KEY_2 }, | ||
3264 | { 0x1e03, KEY_3 }, | ||
3265 | { 0x1e04, KEY_4 }, | ||
3266 | { 0x1e05, KEY_5 }, | ||
3267 | { 0x1e06, KEY_6 }, | ||
3268 | { 0x1e07, KEY_7 }, | ||
3269 | { 0x1e08, KEY_8 }, | ||
3270 | { 0x1e09, KEY_9 }, | ||
3271 | |||
3272 | { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ | ||
3273 | { 0x1e0b, KEY_RED }, /* red button */ | ||
3274 | { 0x1e0c, KEY_RADIO }, | ||
3275 | { 0x1e0d, KEY_MENU }, | ||
3276 | { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ | ||
3277 | { 0x1e0f, KEY_MUTE }, | ||
3278 | { 0x1e10, KEY_VOLUMEUP }, | ||
3279 | { 0x1e11, KEY_VOLUMEDOWN }, | ||
3280 | { 0x1e12, KEY_PREVIOUS }, /* previous channel */ | ||
3281 | { 0x1e14, KEY_UP }, | ||
3282 | { 0x1e15, KEY_DOWN }, | ||
3283 | { 0x1e16, KEY_LEFT }, | ||
3284 | { 0x1e17, KEY_RIGHT }, | ||
3285 | { 0x1e18, KEY_VIDEO }, /* Videos */ | ||
3286 | { 0x1e19, KEY_AUDIO }, /* Music */ | ||
3287 | /* 0x1e1a: Pictures - presume this means | ||
3288 | "Multimedia Home Platform" - | ||
3289 | no "PICTURES" key in input.h | ||
3290 | */ | ||
3291 | { 0x1e1a, KEY_MHP }, | ||
3292 | |||
3293 | { 0x1e1b, KEY_EPG }, /* Guide */ | ||
3294 | { 0x1e1c, KEY_TV }, | ||
3295 | { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ | ||
3296 | { 0x1e1f, KEY_EXIT }, /* back/exit */ | ||
3297 | { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ | ||
3298 | { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ | ||
3299 | { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ | ||
3300 | { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ | ||
3301 | { 0x1e25, KEY_ENTER }, /* OK */ | ||
3302 | { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ | ||
3303 | { 0x1e29, KEY_BLUE }, /* blue key */ | ||
3304 | { 0x1e2e, KEY_GREEN }, /* green button */ | ||
3305 | { 0x1e30, KEY_PAUSE }, /* pause */ | ||
3306 | { 0x1e32, KEY_REWIND }, /* backward << */ | ||
3307 | { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ | ||
3308 | { 0x1e35, KEY_PLAY }, | ||
3309 | { 0x1e36, KEY_STOP }, | ||
3310 | { 0x1e37, KEY_RECORD }, /* recording */ | ||
3311 | { 0x1e38, KEY_YELLOW }, /* yellow key */ | ||
3312 | { 0x1e3b, KEY_SELECT }, /* top right button */ | ||
3313 | { 0x1e3c, KEY_ZOOM }, /* full */ | ||
3314 | { 0x1e3d, KEY_POWER }, /* system power (green button) */ | ||
3315 | }; | ||
3316 | |||
3317 | struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = { | ||
3318 | .scan = ir_codes_rc5_hauppauge_new, | ||
3319 | .size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new), | ||
3320 | .ir_type = IR_TYPE_RC5, | ||
3321 | }; | ||
3322 | EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table); | ||
3323 | |||
3324 | /* Terratec Cinergy Hybrid T USB XS FM | ||
3325 | Mauro Carvalho Chehab <mchehab@redhat.com> | ||
3326 | */ | ||
3327 | static struct ir_scancode ir_codes_nec_terratec_cinergy_xs[] = { | ||
3328 | { 0x1441, KEY_HOME}, | ||
3329 | { 0x1401, KEY_POWER2}, | ||
3330 | |||
3331 | { 0x1442, KEY_MENU}, /* DVD menu */ | ||
3332 | { 0x1443, KEY_SUBTITLE}, | ||
3333 | { 0x1444, KEY_TEXT}, /* Teletext */ | ||
3334 | { 0x1445, KEY_DELETE}, | ||
3335 | |||
3336 | { 0x1402, KEY_1}, | ||
3337 | { 0x1403, KEY_2}, | ||
3338 | { 0x1404, KEY_3}, | ||
3339 | { 0x1405, KEY_4}, | ||
3340 | { 0x1406, KEY_5}, | ||
3341 | { 0x1407, KEY_6}, | ||
3342 | { 0x1408, KEY_7}, | ||
3343 | { 0x1409, KEY_8}, | ||
3344 | { 0x140a, KEY_9}, | ||
3345 | { 0x140c, KEY_0}, | ||
3346 | |||
3347 | { 0x140b, KEY_TUNER}, /* AV */ | ||
3348 | { 0x140d, KEY_MODE}, /* A.B */ | ||
3349 | |||
3350 | { 0x1446, KEY_TV}, | ||
3351 | { 0x1447, KEY_DVD}, | ||
3352 | { 0x1449, KEY_VIDEO}, | ||
3353 | { 0x144a, KEY_RADIO}, /* Music */ | ||
3354 | { 0x144b, KEY_CAMERA}, /* PIC */ | ||
3355 | |||
3356 | { 0x1410, KEY_UP}, | ||
3357 | { 0x1411, KEY_LEFT}, | ||
3358 | { 0x1412, KEY_OK}, | ||
3359 | { 0x1413, KEY_RIGHT}, | ||
3360 | { 0x1414, KEY_DOWN}, | ||
3361 | |||
3362 | { 0x140f, KEY_EPG}, | ||
3363 | { 0x1416, KEY_INFO}, | ||
3364 | { 0x144d, KEY_BACKSPACE}, | ||
3365 | |||
3366 | { 0x141c, KEY_VOLUMEUP}, | ||
3367 | { 0x141e, KEY_VOLUMEDOWN}, | ||
3368 | |||
3369 | { 0x144c, KEY_PLAY}, | ||
3370 | { 0x141d, KEY_MUTE}, | ||
3371 | |||
3372 | { 0x141b, KEY_CHANNELUP}, | ||
3373 | { 0x141f, KEY_CHANNELDOWN}, | ||
3374 | |||
3375 | { 0x1417, KEY_RED}, | ||
3376 | { 0x1418, KEY_GREEN}, | ||
3377 | { 0x1419, KEY_YELLOW}, | ||
3378 | { 0x141a, KEY_BLUE}, | ||
3379 | |||
3380 | { 0x1458, KEY_RECORD}, | ||
3381 | { 0x1448, KEY_STOP}, | ||
3382 | { 0x1440, KEY_PAUSE}, | ||
3383 | |||
3384 | { 0x1454, KEY_LAST}, | ||
3385 | { 0x144e, KEY_REWIND}, | ||
3386 | { 0x144f, KEY_FASTFORWARD}, | ||
3387 | { 0x145c, KEY_NEXT}, | ||
3388 | }; | ||
3389 | struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = { | ||
3390 | .scan = ir_codes_nec_terratec_cinergy_xs, | ||
3391 | .size = ARRAY_SIZE(ir_codes_nec_terratec_cinergy_xs), | ||
3392 | .ir_type = IR_TYPE_NEC, | ||
3393 | }; | ||
3394 | EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table); | ||
3395 | |||
diff --git a/drivers/media/common/ir-keytable.c b/drivers/media/IR/ir-keytable.c index 26ce5bc2fdd5..bff7a5356037 100644 --- a/drivers/media/common/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c | |||
@@ -1,10 +1,19 @@ | |||
1 | /* ir-register.c - handle IR scancode->keycode tables | 1 | /* ir-register.c - handle IR scancode->keycode tables |
2 | * | 2 | * |
3 | * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com> | 3 | * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation version 2 of the License. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
4 | */ | 13 | */ |
5 | 14 | ||
6 | #include <linux/usb/input.h> | ||
7 | 15 | ||
16 | #include <linux/usb/input.h> | ||
8 | #include <media/ir-common.h> | 17 | #include <media/ir-common.h> |
9 | 18 | ||
10 | #define IR_TAB_MIN_SIZE 32 | 19 | #define IR_TAB_MIN_SIZE 32 |
@@ -72,6 +81,7 @@ int ir_roundup_tablesize(int n_elems) | |||
72 | 81 | ||
73 | return n_elems; | 82 | return n_elems; |
74 | } | 83 | } |
84 | EXPORT_SYMBOL_GPL(ir_roundup_tablesize); | ||
75 | 85 | ||
76 | /** | 86 | /** |
77 | * ir_copy_table() - copies a keytable, discarding the unused entries | 87 | * ir_copy_table() - copies a keytable, discarding the unused entries |
@@ -100,6 +110,7 @@ int ir_copy_table(struct ir_scancode_table *destin, | |||
100 | 110 | ||
101 | return 0; | 111 | return 0; |
102 | } | 112 | } |
113 | EXPORT_SYMBOL_GPL(ir_copy_table); | ||
103 | 114 | ||
104 | /** | 115 | /** |
105 | * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table | 116 | * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table |
@@ -114,7 +125,8 @@ static int ir_getkeycode(struct input_dev *dev, | |||
114 | int scancode, int *keycode) | 125 | int scancode, int *keycode) |
115 | { | 126 | { |
116 | int elem; | 127 | int elem; |
117 | struct ir_scancode_table *rc_tab = input_get_drvdata(dev); | 128 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); |
129 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
118 | 130 | ||
119 | elem = ir_seek_table(rc_tab, scancode); | 131 | elem = ir_seek_table(rc_tab, scancode); |
120 | if (elem >= 0) { | 132 | if (elem >= 0) { |
@@ -136,7 +148,6 @@ static int ir_getkeycode(struct input_dev *dev, | |||
136 | return 0; | 148 | return 0; |
137 | } | 149 | } |
138 | 150 | ||
139 | |||
140 | /** | 151 | /** |
141 | * ir_is_resize_needed() - Check if the table needs rezise | 152 | * ir_is_resize_needed() - Check if the table needs rezise |
142 | * @table: keycode table that may need to resize | 153 | * @table: keycode table that may need to resize |
@@ -286,7 +297,8 @@ static int ir_setkeycode(struct input_dev *dev, | |||
286 | int scancode, int keycode) | 297 | int scancode, int keycode) |
287 | { | 298 | { |
288 | int rc = 0; | 299 | int rc = 0; |
289 | struct ir_scancode_table *rc_tab = input_get_drvdata(dev); | 300 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); |
301 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
290 | struct ir_scancode *keymap = rc_tab->scan; | 302 | struct ir_scancode *keymap = rc_tab->scan; |
291 | unsigned long flags; | 303 | unsigned long flags; |
292 | 304 | ||
@@ -360,7 +372,8 @@ static int ir_setkeycode(struct input_dev *dev, | |||
360 | */ | 372 | */ |
361 | u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) | 373 | u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) |
362 | { | 374 | { |
363 | struct ir_scancode_table *rc_tab = input_get_drvdata(dev); | 375 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); |
376 | struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | ||
364 | struct ir_scancode *keymap = rc_tab->scan; | 377 | struct ir_scancode *keymap = rc_tab->scan; |
365 | int elem; | 378 | int elem; |
366 | 379 | ||
@@ -378,9 +391,10 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) | |||
378 | /* Reports userspace that an unknown keycode were got */ | 391 | /* Reports userspace that an unknown keycode were got */ |
379 | return KEY_RESERVED; | 392 | return KEY_RESERVED; |
380 | } | 393 | } |
394 | EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); | ||
381 | 395 | ||
382 | /** | 396 | /** |
383 | * ir_set_keycode_table() - sets the IR keycode table and add the handlers | 397 | * ir_input_register() - sets the IR keycode table and add the handlers |
384 | * for keymap table get/set | 398 | * for keymap table get/set |
385 | * @input_dev: the struct input_dev descriptor of the device | 399 | * @input_dev: the struct input_dev descriptor of the device |
386 | * @rc_tab: the struct ir_scancode_table table of scancode/keymap | 400 | * @rc_tab: the struct ir_scancode_table table of scancode/keymap |
@@ -389,17 +403,34 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) | |||
389 | * an IR. | 403 | * an IR. |
390 | * It should be called before registering the IR device. | 404 | * It should be called before registering the IR device. |
391 | */ | 405 | */ |
392 | int ir_set_keycode_table(struct input_dev *input_dev, | 406 | int ir_input_register(struct input_dev *input_dev, |
393 | struct ir_scancode_table *rc_tab) | 407 | struct ir_scancode_table *rc_tab) |
394 | { | 408 | { |
395 | struct ir_scancode *keymap = rc_tab->scan; | 409 | struct ir_input_dev *ir_dev; |
396 | int i; | 410 | struct ir_scancode *keymap = rc_tab->scan; |
397 | 411 | int i, rc; | |
398 | spin_lock_init(&rc_tab->lock); | ||
399 | 412 | ||
400 | if (rc_tab->scan == NULL || !rc_tab->size) | 413 | if (rc_tab->scan == NULL || !rc_tab->size) |
401 | return -EINVAL; | 414 | return -EINVAL; |
402 | 415 | ||
416 | ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL); | ||
417 | if (!ir_dev) | ||
418 | return -ENOMEM; | ||
419 | |||
420 | spin_lock_init(&rc_tab->lock); | ||
421 | |||
422 | ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size); | ||
423 | ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size * | ||
424 | sizeof(struct ir_scancode), GFP_KERNEL); | ||
425 | if (!ir_dev->rc_tab.scan) | ||
426 | return -ENOMEM; | ||
427 | |||
428 | IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", | ||
429 | ir_dev->rc_tab.size, | ||
430 | ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan)); | ||
431 | |||
432 | ir_copy_table(&ir_dev->rc_tab, rc_tab); | ||
433 | |||
403 | /* set the bits for the keys */ | 434 | /* set the bits for the keys */ |
404 | IR_dprintk(1, "key map size: %d\n", rc_tab->size); | 435 | IR_dprintk(1, "key map size: %d\n", rc_tab->size); |
405 | for (i = 0; i < rc_tab->size; i++) { | 436 | for (i = 0; i < rc_tab->size; i++) { |
@@ -407,23 +438,48 @@ int ir_set_keycode_table(struct input_dev *input_dev, | |||
407 | i, keymap[i].keycode); | 438 | i, keymap[i].keycode); |
408 | set_bit(keymap[i].keycode, input_dev->keybit); | 439 | set_bit(keymap[i].keycode, input_dev->keybit); |
409 | } | 440 | } |
441 | clear_bit(0, input_dev->keybit); | ||
442 | |||
443 | set_bit(EV_KEY, input_dev->evbit); | ||
410 | 444 | ||
411 | input_dev->getkeycode = ir_getkeycode; | 445 | input_dev->getkeycode = ir_getkeycode; |
412 | input_dev->setkeycode = ir_setkeycode; | 446 | input_dev->setkeycode = ir_setkeycode; |
413 | input_set_drvdata(input_dev, rc_tab); | 447 | input_set_drvdata(input_dev, ir_dev); |
414 | 448 | ||
415 | return 0; | 449 | rc = input_register_device(input_dev); |
450 | if (rc < 0) { | ||
451 | kfree(rc_tab->scan); | ||
452 | kfree(ir_dev); | ||
453 | input_set_drvdata(input_dev, NULL); | ||
454 | } | ||
455 | |||
456 | return rc; | ||
416 | } | 457 | } |
458 | EXPORT_SYMBOL_GPL(ir_input_register); | ||
417 | 459 | ||
418 | void ir_input_free(struct input_dev *dev) | 460 | void ir_input_unregister(struct input_dev *dev) |
419 | { | 461 | { |
420 | struct ir_scancode_table *rc_tab = input_get_drvdata(dev); | 462 | struct ir_input_dev *ir_dev = input_get_drvdata(dev); |
463 | struct ir_scancode_table *rc_tab; | ||
464 | |||
465 | if (!ir_dev) | ||
466 | return; | ||
421 | 467 | ||
422 | IR_dprintk(1, "Freed keycode table\n"); | 468 | IR_dprintk(1, "Freed keycode table\n"); |
423 | 469 | ||
470 | rc_tab = &ir_dev->rc_tab; | ||
424 | rc_tab->size = 0; | 471 | rc_tab->size = 0; |
425 | kfree(rc_tab->scan); | 472 | kfree(rc_tab->scan); |
426 | rc_tab->scan = NULL; | 473 | rc_tab->scan = NULL; |
474 | |||
475 | kfree(ir_dev); | ||
476 | input_unregister_device(dev); | ||
427 | } | 477 | } |
428 | EXPORT_SYMBOL_GPL(ir_input_free); | 478 | EXPORT_SYMBOL_GPL(ir_input_unregister); |
479 | |||
480 | int ir_core_debug; /* ir_debug level (0,1,2) */ | ||
481 | EXPORT_SYMBOL_GPL(ir_core_debug); | ||
482 | module_param_named(debug, ir_core_debug, int, 0644); | ||
429 | 483 | ||
484 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
485 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ba69beeb0e21..a28541b2b1a2 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -99,6 +99,7 @@ config VIDEO_MEDIA | |||
99 | comment "Multimedia drivers" | 99 | comment "Multimedia drivers" |
100 | 100 | ||
101 | source "drivers/media/common/Kconfig" | 101 | source "drivers/media/common/Kconfig" |
102 | source "drivers/media/IR/Kconfig" | ||
102 | 103 | ||
103 | # | 104 | # |
104 | # Tuner drivers for DVB and V4L | 105 | # Tuner drivers for DVB and V4L |
diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 09a829d8a7e7..499b0810d019 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the kernel multimedia device drivers. | 2 | # Makefile for the kernel multimedia device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += common/ video/ | 5 | obj-y += common/ IR/ video/ |
6 | 6 | ||
7 | obj-$(CONFIG_VIDEO_DEV) += radio/ | 7 | obj-$(CONFIG_VIDEO_DEV) += radio/ |
8 | obj-$(CONFIG_DVB_CORE) += dvb/ | 8 | obj-$(CONFIG_DVB_CORE) += dvb/ |
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 169b337b7c9d..e3ec9639321b 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile | |||
@@ -1,8 +1,6 @@ | |||
1 | saa7146-objs := saa7146_i2c.o saa7146_core.o | 1 | saa7146-objs := saa7146_i2c.o saa7146_core.o |
2 | saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o | 2 | saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o |
3 | ir-common-objs := ir-functions.o ir-keymaps.o ir-keytable.o | ||
4 | 3 | ||
5 | obj-y += tuners/ | 4 | obj-y += tuners/ |
6 | obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o | 5 | obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o |
7 | obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o | 6 | obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o |
8 | obj-$(CONFIG_VIDEO_IR) += ir-common.o | ||
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 620f655fa9c5..7364b9642d00 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c | |||
@@ -1,7 +1,5 @@ | |||
1 | #include <media/saa7146_vv.h> | 1 | #include <media/saa7146_vv.h> |
2 | 2 | ||
3 | #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) | ||
4 | |||
5 | /****************************************************************************/ | 3 | /****************************************************************************/ |
6 | /* resource management functions, shamelessly stolen from saa7134 driver */ | 4 | /* resource management functions, shamelessly stolen from saa7134 driver */ |
7 | 5 | ||
@@ -194,43 +192,24 @@ void saa7146_buffer_timeout(unsigned long data) | |||
194 | 192 | ||
195 | static int fops_open(struct file *file) | 193 | static int fops_open(struct file *file) |
196 | { | 194 | { |
197 | unsigned int minor = video_devdata(file)->minor; | 195 | struct video_device *vdev = video_devdata(file); |
198 | struct saa7146_dev *h = NULL, *dev = NULL; | 196 | struct saa7146_dev *dev = video_drvdata(file); |
199 | struct list_head *list; | ||
200 | struct saa7146_fh *fh = NULL; | 197 | struct saa7146_fh *fh = NULL; |
201 | int result = 0; | 198 | int result = 0; |
202 | 199 | ||
203 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 200 | enum v4l2_buf_type type; |
204 | 201 | ||
205 | DEB_EE(("file:%p, minor:%d\n", file, minor)); | 202 | DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); |
206 | 203 | ||
207 | if (mutex_lock_interruptible(&saa7146_devices_lock)) | 204 | if (mutex_lock_interruptible(&saa7146_devices_lock)) |
208 | return -ERESTARTSYS; | 205 | return -ERESTARTSYS; |
209 | 206 | ||
210 | list_for_each(list,&saa7146_devices) { | ||
211 | h = list_entry(list, struct saa7146_dev, item); | ||
212 | if( NULL == h->vv_data ) { | ||
213 | DEB_D(("device %p has not registered video devices.\n",h)); | ||
214 | continue; | ||
215 | } | ||
216 | DEB_D(("trying: %p @ major %d,%d\n",h,h->vv_data->video_minor,h->vv_data->vbi_minor)); | ||
217 | |||
218 | if (h->vv_data->video_minor == minor) { | ||
219 | dev = h; | ||
220 | } | ||
221 | if (h->vv_data->vbi_minor == minor) { | ||
222 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
223 | dev = h; | ||
224 | } | ||
225 | } | ||
226 | if (NULL == dev) { | ||
227 | DEB_S(("no such video device.\n")); | ||
228 | result = -ENODEV; | ||
229 | goto out; | ||
230 | } | ||
231 | |||
232 | DEB_D(("using: %p\n",dev)); | 207 | DEB_D(("using: %p\n",dev)); |
233 | 208 | ||
209 | type = vdev->vfl_type == VFL_TYPE_GRABBER | ||
210 | ? V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
211 | : V4L2_BUF_TYPE_VBI_CAPTURE; | ||
212 | |||
234 | /* check if an extension is registered */ | 213 | /* check if an extension is registered */ |
235 | if( NULL == dev->ext ) { | 214 | if( NULL == dev->ext ) { |
236 | DEB_S(("no extension registered for this device.\n")); | 215 | DEB_S(("no extension registered for this device.\n")); |
@@ -474,9 +453,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) | |||
474 | configuration data) */ | 453 | configuration data) */ |
475 | dev->ext_vv_data = ext_vv; | 454 | dev->ext_vv_data = ext_vv; |
476 | 455 | ||
477 | vv->video_minor = -1; | ||
478 | vv->vbi_minor = -1; | ||
479 | |||
480 | vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); | 456 | vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); |
481 | if( NULL == vv->d_clipping.cpu_addr ) { | 457 | if( NULL == vv->d_clipping.cpu_addr ) { |
482 | ERR(("out of memory. aborting.\n")); | 458 | ERR(("out of memory. aborting.\n")); |
@@ -515,7 +491,6 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release); | |||
515 | int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | 491 | int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, |
516 | char *name, int type) | 492 | char *name, int type) |
517 | { | 493 | { |
518 | struct saa7146_vv *vv = dev->vv_data; | ||
519 | struct video_device *vfd; | 494 | struct video_device *vfd; |
520 | int err; | 495 | int err; |
521 | int i; | 496 | int i; |
@@ -543,15 +518,8 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | |||
543 | return err; | 518 | return err; |
544 | } | 519 | } |
545 | 520 | ||
546 | if( VFL_TYPE_GRABBER == type ) { | 521 | INFO(("%s: registered device %s [v4l2]\n", |
547 | vv->video_minor = vfd->minor; | 522 | dev->name, video_device_node_name(vfd))); |
548 | INFO(("%s: registered device video%d [v4l2]\n", | ||
549 | dev->name, vfd->num)); | ||
550 | } else { | ||
551 | vv->vbi_minor = vfd->minor; | ||
552 | INFO(("%s: registered device vbi%d [v4l2]\n", | ||
553 | dev->name, vfd->num)); | ||
554 | } | ||
555 | 523 | ||
556 | *vid = vfd; | 524 | *vid = vfd; |
557 | return 0; | 525 | return 0; |
@@ -560,16 +528,8 @@ EXPORT_SYMBOL_GPL(saa7146_register_device); | |||
560 | 528 | ||
561 | int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) | 529 | int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) |
562 | { | 530 | { |
563 | struct saa7146_vv *vv = dev->vv_data; | ||
564 | |||
565 | DEB_EE(("dev:%p\n",dev)); | 531 | DEB_EE(("dev:%p\n",dev)); |
566 | 532 | ||
567 | if ((*vid)->vfl_type == VFL_TYPE_GRABBER) { | ||
568 | vv->video_minor = -1; | ||
569 | } else { | ||
570 | vv->vbi_minor = -1; | ||
571 | } | ||
572 | |||
573 | video_unregister_device(*vid); | 533 | video_unregister_device(*vid); |
574 | *vid = NULL; | 534 | *vid = NULL; |
575 | 535 | ||
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 53e3f2a7d31a..f0f483ac8b89 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c | |||
@@ -589,7 +589,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) | |||
589 | snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), | 589 | snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), |
590 | "pci-%s/ir0", pci_name(dm1105->pdev)); | 590 | "pci-%s/ir0", pci_name(dm1105->pdev)); |
591 | 591 | ||
592 | err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes); | 592 | err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type); |
593 | if (err < 0) { | 593 | if (err < 0) { |
594 | input_free_device(input_dev); | 594 | input_free_device(input_dev); |
595 | return err; | 595 | return err; |
@@ -611,20 +611,14 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) | |||
611 | 611 | ||
612 | INIT_WORK(&dm1105->ir.work, dm1105_emit_key); | 612 | INIT_WORK(&dm1105->ir.work, dm1105_emit_key); |
613 | 613 | ||
614 | err = input_register_device(input_dev); | 614 | err = ir_input_register(input_dev, ir_codes); |
615 | if (err) { | ||
616 | ir_input_free(input_dev); | ||
617 | input_free_device(input_dev); | ||
618 | return err; | ||
619 | } | ||
620 | 615 | ||
621 | return 0; | 616 | return err; |
622 | } | 617 | } |
623 | 618 | ||
624 | void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) | 619 | void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) |
625 | { | 620 | { |
626 | ir_input_free(dm1105->ir.input_dev); | 621 | ir_input_unregister(dm1105->ir.input_dev); |
627 | input_unregister_device(dm1105->ir.input_dev); | ||
628 | } | 622 | } |
629 | 623 | ||
630 | static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) | 624 | static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) |
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2dee1bf73577..1b249897c9fb 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -265,9 +265,13 @@ config DVB_USB_DW2102 | |||
265 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE | 265 | select DVB_TDA10021 if !DVB_FE_CUSTOMISE |
266 | select DVB_MT312 if !DVB_FE_CUSTOMISE | 266 | select DVB_MT312 if !DVB_FE_CUSTOMISE |
267 | select DVB_ZL10039 if !DVB_FE_CUSTOMISE | 267 | select DVB_ZL10039 if !DVB_FE_CUSTOMISE |
268 | select DVB_DS3000 if !DVB_FE_CUSTOMISE | ||
269 | select DVB_STB6100 if !DVB_FE_CUSTOMISE | ||
270 | select DVB_STV6110 if !DVB_FE_CUSTOMISE | ||
271 | select DVB_STV0900 if !DVB_FE_CUSTOMISE | ||
268 | help | 272 | help |
269 | Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers | 273 | Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 |
270 | and the TeVii S650, S630. | 274 | receivers. |
271 | 275 | ||
272 | config DVB_USB_CINERGY_T2 | 276 | config DVB_USB_CINERGY_T2 |
273 | tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" | 277 | tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" |
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 8b544fe79b0d..495a90577c5f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h | |||
@@ -20,20 +20,22 @@ extern int dvb_usb_dib0700_debug; | |||
20 | #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) | 20 | #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) |
21 | #define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) | 21 | #define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) |
22 | 22 | ||
23 | #define REQUEST_I2C_READ 0x2 | 23 | #define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ |
24 | #define REQUEST_I2C_WRITE 0x3 | 24 | /* higher than 1.21 */ |
25 | #define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ | 25 | #define REQUEST_I2C_READ 0x2 |
26 | #define REQUEST_JUMPRAM 0x8 | 26 | #define REQUEST_I2C_WRITE 0x3 |
27 | #define REQUEST_SET_CLOCK 0xB | 27 | #define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ |
28 | #define REQUEST_SET_GPIO 0xC | 28 | #define REQUEST_JUMPRAM 0x8 |
29 | #define REQUEST_ENABLE_VIDEO 0xF | 29 | #define REQUEST_SET_CLOCK 0xB |
30 | #define REQUEST_SET_GPIO 0xC | ||
31 | #define REQUEST_ENABLE_VIDEO 0xF | ||
30 | // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) | 32 | // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) |
31 | // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) | 33 | // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) |
32 | // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) | 34 | // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) |
33 | #define REQUEST_SET_RC 0x11 | 35 | #define REQUEST_SET_RC 0x11 |
34 | #define REQUEST_NEW_I2C_READ 0x12 | 36 | #define REQUEST_NEW_I2C_READ 0x12 |
35 | #define REQUEST_NEW_I2C_WRITE 0x13 | 37 | #define REQUEST_NEW_I2C_WRITE 0x13 |
36 | #define REQUEST_GET_VERSION 0x15 | 38 | #define REQUEST_GET_VERSION 0x15 |
37 | 39 | ||
38 | struct dib0700_state { | 40 | struct dib0700_state { |
39 | u8 channel_state; | 41 | u8 channel_state; |
@@ -44,6 +46,8 @@ struct dib0700_state { | |||
44 | u8 is_dib7000pc; | 46 | u8 is_dib7000pc; |
45 | u8 fw_use_new_i2c_api; | 47 | u8 fw_use_new_i2c_api; |
46 | u8 disable_streaming_master_mode; | 48 | u8 disable_streaming_master_mode; |
49 | u32 fw_version; | ||
50 | u32 nb_packet_buffer_size; | ||
47 | }; | 51 | }; |
48 | 52 | ||
49 | extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, | 53 | extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, |
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index db7f7f79a66c..0d3c9a9a33be 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c | |||
@@ -17,6 +17,14 @@ int dvb_usb_dib0700_ir_proto = 1; | |||
17 | module_param(dvb_usb_dib0700_ir_proto, int, 0644); | 17 | module_param(dvb_usb_dib0700_ir_proto, int, 0644); |
18 | MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); | 18 | MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); |
19 | 19 | ||
20 | static int nb_packet_buffer_size = 21; | ||
21 | module_param(nb_packet_buffer_size, int, 0644); | ||
22 | MODULE_PARM_DESC(nb_packet_buffer_size, | ||
23 | "Set the dib0700 driver data buffer size. This parameter " | ||
24 | "corresponds to the number of TS packets. The actual size of " | ||
25 | "the data buffer corresponds to this parameter " | ||
26 | "multiplied by 188 (default: 21)"); | ||
27 | |||
20 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 28 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
21 | 29 | ||
22 | 30 | ||
@@ -28,10 +36,14 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, | |||
28 | REQUEST_GET_VERSION, | 36 | REQUEST_GET_VERSION, |
29 | USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, | 37 | USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, |
30 | b, sizeof(b), USB_CTRL_GET_TIMEOUT); | 38 | b, sizeof(b), USB_CTRL_GET_TIMEOUT); |
31 | *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; | 39 | if (hwversion != NULL) |
32 | *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; | 40 | *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; |
33 | *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; | 41 | if (romversion != NULL) |
34 | *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; | 42 | *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; |
43 | if (ramversion != NULL) | ||
44 | *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; | ||
45 | if (fwtype != NULL) | ||
46 | *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; | ||
35 | return ret; | 47 | return ret; |
36 | } | 48 | } |
37 | 49 | ||
@@ -97,6 +109,27 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ | |||
97 | return dib0700_ctrl_wr(d,buf,3); | 109 | return dib0700_ctrl_wr(d,buf,3); |
98 | } | 110 | } |
99 | 111 | ||
112 | static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) | ||
113 | { | ||
114 | struct dib0700_state *st = d->priv; | ||
115 | u8 b[3]; | ||
116 | int ret; | ||
117 | |||
118 | if (st->fw_version >= 0x10201) { | ||
119 | b[0] = REQUEST_SET_USB_XFER_LEN; | ||
120 | b[1] = (nb_ts_packets >> 8)&0xff; | ||
121 | b[2] = nb_ts_packets & 0xff; | ||
122 | |||
123 | deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); | ||
124 | |||
125 | ret = dib0700_ctrl_wr(d, b, 3); | ||
126 | } else { | ||
127 | deb_info("this firmware does not allow to change the USB xfer len\n"); | ||
128 | ret = -EIO; | ||
129 | } | ||
130 | return ret; | ||
131 | } | ||
132 | |||
100 | /* | 133 | /* |
101 | * I2C master xfer function (supported in 1.20 firmware) | 134 | * I2C master xfer function (supported in 1.20 firmware) |
102 | */ | 135 | */ |
@@ -328,7 +361,9 @@ static int dib0700_jumpram(struct usb_device *udev, u32 address) | |||
328 | int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) | 361 | int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) |
329 | { | 362 | { |
330 | struct hexline hx; | 363 | struct hexline hx; |
331 | int pos = 0, ret, act_len; | 364 | int pos = 0, ret, act_len, i, adap_num; |
365 | u8 b[16]; | ||
366 | u32 fw_version; | ||
332 | 367 | ||
333 | u8 buf[260]; | 368 | u8 buf[260]; |
334 | 369 | ||
@@ -364,6 +399,34 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw | |||
364 | } else | 399 | } else |
365 | ret = -EIO; | 400 | ret = -EIO; |
366 | 401 | ||
402 | /* the number of ts packet has to be at least 1 */ | ||
403 | if (nb_packet_buffer_size < 1) | ||
404 | nb_packet_buffer_size = 1; | ||
405 | |||
406 | /* get the fimware version */ | ||
407 | usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
408 | REQUEST_GET_VERSION, | ||
409 | USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, | ||
410 | b, sizeof(b), USB_CTRL_GET_TIMEOUT); | ||
411 | fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; | ||
412 | |||
413 | /* set the buffer size - DVB-USB is allocating URB buffers | ||
414 | * only after the firwmare download was successful */ | ||
415 | for (i = 0; i < dib0700_device_count; i++) { | ||
416 | for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; | ||
417 | adap_num++) { | ||
418 | if (fw_version >= 0x10201) | ||
419 | dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; | ||
420 | else { | ||
421 | /* for fw version older than 1.20.1, | ||
422 | * the buffersize has to be n times 512 */ | ||
423 | dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; | ||
424 | if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) | ||
425 | dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; | ||
426 | } | ||
427 | } | ||
428 | } | ||
429 | |||
367 | return ret; | 430 | return ret; |
368 | } | 431 | } |
369 | 432 | ||
@@ -371,6 +434,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
371 | { | 434 | { |
372 | struct dib0700_state *st = adap->dev->priv; | 435 | struct dib0700_state *st = adap->dev->priv; |
373 | u8 b[4]; | 436 | u8 b[4]; |
437 | int ret; | ||
438 | |||
439 | if ((onoff != 0) && (st->fw_version >= 0x10201)) { | ||
440 | /* for firmware later than 1.20.1, | ||
441 | * the USB xfer length can be set */ | ||
442 | ret = dib0700_set_usb_xfer_len(adap->dev, | ||
443 | st->nb_packet_buffer_size); | ||
444 | if (ret < 0) { | ||
445 | deb_info("can not set the USB xfer len\n"); | ||
446 | return ret; | ||
447 | } | ||
448 | } | ||
374 | 449 | ||
375 | b[0] = REQUEST_ENABLE_VIDEO; | 450 | b[0] = REQUEST_ENABLE_VIDEO; |
376 | b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ | 451 | b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ |
@@ -415,9 +490,21 @@ static int dib0700_probe(struct usb_interface *intf, | |||
415 | 490 | ||
416 | for (i = 0; i < dib0700_device_count; i++) | 491 | for (i = 0; i < dib0700_device_count; i++) |
417 | if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, | 492 | if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, |
418 | &dev, adapter_nr) == 0) | 493 | &dev, adapter_nr) == 0) { |
419 | { | 494 | struct dib0700_state *st = dev->priv; |
495 | u32 hwversion, romversion, fw_version, fwtype; | ||
496 | |||
497 | dib0700_get_version(dev, &hwversion, &romversion, | ||
498 | &fw_version, &fwtype); | ||
499 | |||
500 | deb_info("Firmware version: %x, %d, 0x%x, %d\n", | ||
501 | hwversion, romversion, fw_version, fwtype); | ||
502 | |||
503 | st->fw_version = fw_version; | ||
504 | st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; | ||
505 | |||
420 | dib0700_rc_setup(dev); | 506 | dib0700_rc_setup(dev); |
507 | |||
421 | return 0; | 508 | return 0; |
422 | } | 509 | } |
423 | 510 | ||
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 684146f98eb7..44972d01bbd0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "xc5000.h" | 18 | #include "xc5000.h" |
19 | #include "s5h1411.h" | 19 | #include "s5h1411.h" |
20 | #include "dib0070.h" | 20 | #include "dib0070.h" |
21 | #include "dib0090.h" | ||
21 | #include "lgdt3305.h" | 22 | #include "lgdt3305.h" |
22 | #include "mxl5007t.h" | 23 | #include "mxl5007t.h" |
23 | 24 | ||
@@ -130,93 +131,95 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) | |||
130 | /* MT226x */ | 131 | /* MT226x */ |
131 | static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { | 132 | static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { |
132 | { | 133 | { |
133 | BAND_UHF, // band_caps | 134 | BAND_UHF, |
134 | 135 | ||
135 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, | 136 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, |
136 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ | 137 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ |
137 | (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup | 138 | (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) |
138 | 139 | | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), | |
139 | 1130, // inv_gain | 140 | |
140 | 21, // time_stabiliz | 141 | 1130, |
141 | 142 | 21, | |
142 | 0, // alpha_level | 143 | |
143 | 118, // thlock | 144 | 0, |
144 | 145 | 118, | |
145 | 0, // wbd_inv | 146 | |
146 | 3530, // wbd_ref | 147 | 0, |
147 | 1, // wbd_sel | 148 | 3530, |
148 | 0, // wbd_alpha | 149 | 1, |
149 | 150 | 0, | |
150 | 65535, // agc1_max | 151 | |
151 | 33770, // agc1_min | 152 | 65535, |
152 | 65535, // agc2_max | 153 | 33770, |
153 | 23592, // agc2_min | 154 | 65535, |
154 | 155 | 23592, | |
155 | 0, // agc1_pt1 | 156 | |
156 | 62, // agc1_pt2 | 157 | 0, |
157 | 255, // agc1_pt3 | 158 | 62, |
158 | 64, // agc1_slope1 | 159 | 255, |
159 | 64, // agc1_slope2 | 160 | 64, |
160 | 132, // agc2_pt1 | 161 | 64, |
161 | 192, // agc2_pt2 | 162 | 132, |
162 | 80, // agc2_slope1 | 163 | 192, |
163 | 80, // agc2_slope2 | 164 | 80, |
164 | 165 | 80, | |
165 | 17, // alpha_mant | 166 | |
166 | 27, // alpha_exp | 167 | 17, |
167 | 23, // beta_mant | 168 | 27, |
168 | 51, // beta_exp | 169 | 23, |
169 | 170 | 51, | |
170 | 1, // perform_agc_softsplit | 171 | |
172 | 1, | ||
171 | }, { | 173 | }, { |
172 | BAND_VHF | BAND_LBAND, // band_caps | 174 | BAND_VHF | BAND_LBAND, |
173 | 175 | ||
174 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, | 176 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, |
175 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ | 177 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ |
176 | (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup | 178 | (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) |
177 | 179 | | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), | |
178 | 2372, // inv_gain | 180 | |
179 | 21, // time_stabiliz | 181 | 2372, |
180 | 182 | 21, | |
181 | 0, // alpha_level | 183 | |
182 | 118, // thlock | 184 | 0, |
183 | 185 | 118, | |
184 | 0, // wbd_inv | 186 | |
185 | 3530, // wbd_ref | 187 | 0, |
186 | 1, // wbd_sel | 188 | 3530, |
187 | 0, // wbd_alpha | 189 | 1, |
188 | 190 | 0, | |
189 | 65535, // agc1_max | 191 | |
190 | 0, // agc1_min | 192 | 65535, |
191 | 65535, // agc2_max | 193 | 0, |
192 | 23592, // agc2_min | 194 | 65535, |
193 | 195 | 23592, | |
194 | 0, // agc1_pt1 | 196 | |
195 | 128, // agc1_pt2 | 197 | 0, |
196 | 128, // agc1_pt3 | 198 | 128, |
197 | 128, // agc1_slope1 | 199 | 128, |
198 | 0, // agc1_slope2 | 200 | 128, |
199 | 128, // agc2_pt1 | 201 | 0, |
200 | 253, // agc2_pt2 | 202 | 128, |
201 | 81, // agc2_slope1 | 203 | 253, |
202 | 0, // agc2_slope2 | 204 | 81, |
203 | 205 | 0, | |
204 | 17, // alpha_mant | 206 | |
205 | 27, // alpha_exp | 207 | 17, |
206 | 23, // beta_mant | 208 | 27, |
207 | 51, // beta_exp | 209 | 23, |
208 | 210 | 51, | |
209 | 1, // perform_agc_softsplit | 211 | |
212 | 1, | ||
210 | } | 213 | } |
211 | }; | 214 | }; |
212 | 215 | ||
213 | static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { | 216 | static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { |
214 | 60000, 30000, // internal, sampling | 217 | 60000, 30000, |
215 | 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass | 218 | 1, 8, 3, 1, 0, |
216 | 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo | 219 | 0, 0, 1, 1, 2, |
217 | (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k | 220 | (3 << 14) | (1 << 12) | (524 << 0), |
218 | 0, // ifreq | 221 | 0, |
219 | 20452225, // timf | 222 | 20452225, |
220 | }; | 223 | }; |
221 | 224 | ||
222 | static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { | 225 | static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { |
@@ -605,17 +608,17 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, | |||
605 | } | 608 | } |
606 | break; | 609 | break; |
607 | default: | 610 | default: |
608 | if (actlen != sizeof(buf)) { | 611 | if (actlen != sizeof(buf)) { |
609 | /* We didn't get back the 6 byte message we expected */ | 612 | /* We didn't get back the 6 byte message we expected */ |
610 | err("Unexpected RC response size [%d]", actlen); | 613 | err("Unexpected RC response size [%d]", actlen); |
611 | return -1; | 614 | return -1; |
612 | } | 615 | } |
613 | 616 | ||
614 | poll_reply.report_id = buf[0]; | 617 | poll_reply.report_id = buf[0]; |
615 | poll_reply.data_state = buf[1]; | 618 | poll_reply.data_state = buf[1]; |
616 | poll_reply.system = (buf[2] << 8) | buf[3]; | 619 | poll_reply.system = (buf[2] << 8) | buf[3]; |
617 | poll_reply.data = buf[4]; | 620 | poll_reply.data = buf[4]; |
618 | poll_reply.not_data = buf[5]; | 621 | poll_reply.not_data = buf[5]; |
619 | 622 | ||
620 | break; | 623 | break; |
621 | } | 624 | } |
@@ -632,7 +635,7 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, | |||
632 | /* Find the key in the map */ | 635 | /* Find the key in the map */ |
633 | for (i = 0; i < d->props.rc_key_map_size; i++) { | 636 | for (i = 0; i < d->props.rc_key_map_size; i++) { |
634 | if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) && | 637 | if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) && |
635 | rc5_data(&keymap[i]) == poll_reply.data) { | 638 | rc5_data(&keymap[i]) == poll_reply.data) { |
636 | *event = keymap[i].event; | 639 | *event = keymap[i].event; |
637 | found = 1; | 640 | found = 1; |
638 | break; | 641 | break; |
@@ -641,8 +644,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, | |||
641 | 644 | ||
642 | if (found == 0) { | 645 | if (found == 0) { |
643 | err("Unknown remote controller key: %04x %02x %02x", | 646 | err("Unknown remote controller key: %04x %02x %02x", |
644 | poll_reply.system, | 647 | poll_reply.system, |
645 | poll_reply.data, poll_reply.not_data); | 648 | poll_reply.data, poll_reply.not_data); |
646 | d->last_event = 0; | 649 | d->last_event = 0; |
647 | return 0; | 650 | return 0; |
648 | } | 651 | } |
@@ -933,47 +936,48 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { | |||
933 | 936 | ||
934 | /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ | 937 | /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ |
935 | static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { | 938 | static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { |
936 | BAND_UHF | BAND_VHF, // band_caps | 939 | BAND_UHF | BAND_VHF, |
937 | 940 | ||
938 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, | 941 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, |
939 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ | 942 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ |
940 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup | 943 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
941 | 944 | | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), | |
942 | 712, // inv_gain | 945 | |
943 | 41, // time_stabiliz | 946 | 712, |
944 | 947 | 41, | |
945 | 0, // alpha_level | 948 | |
946 | 118, // thlock | 949 | 0, |
947 | 950 | 118, | |
948 | 0, // wbd_inv | 951 | |
949 | 4095, // wbd_ref | 952 | 0, |
950 | 0, // wbd_sel | 953 | 4095, |
951 | 0, // wbd_alpha | 954 | 0, |
952 | 955 | 0, | |
953 | 42598, // agc1_max | 956 | |
954 | 17694, // agc1_min | 957 | 42598, |
955 | 45875, // agc2_max | 958 | 17694, |
956 | 2621, // agc2_min | 959 | 45875, |
957 | 0, // agc1_pt1 | 960 | 2621, |
958 | 76, // agc1_pt2 | 961 | 0, |
959 | 139, // agc1_pt3 | 962 | 76, |
960 | 52, // agc1_slope1 | 963 | 139, |
961 | 59, // agc1_slope2 | 964 | 52, |
962 | 107, // agc2_pt1 | 965 | 59, |
963 | 172, // agc2_pt2 | 966 | 107, |
964 | 57, // agc2_slope1 | 967 | 172, |
965 | 70, // agc2_slope2 | 968 | 57, |
966 | 969 | 70, | |
967 | 21, // alpha_mant | 970 | |
968 | 25, // alpha_exp | 971 | 21, |
969 | 28, // beta_mant | 972 | 25, |
970 | 48, // beta_exp | 973 | 28, |
971 | 974 | 48, | |
972 | 1, // perform_agc_softsplit | 975 | |
973 | { 0, // split_min | 976 | 1, |
974 | 107, // split_max | 977 | { 0, |
975 | 51800, // global_split_min | 978 | 107, |
976 | 24700 // global_split_max | 979 | 51800, |
980 | 24700 | ||
977 | }, | 981 | }, |
978 | }; | 982 | }; |
979 | 983 | ||
@@ -982,54 +986,55 @@ static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { | |||
982 | 986 | ||
983 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, | 987 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, |
984 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ | 988 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ |
985 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup | 989 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
990 | | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), | ||
986 | 991 | ||
987 | 712, // inv_gain | 992 | 712, |
988 | 41, // time_stabiliz | 993 | 41, |
989 | 994 | ||
990 | 0, // alpha_level | 995 | 0, |
991 | 118, // thlock | 996 | 118, |
992 | 997 | ||
993 | 0, // wbd_inv | 998 | 0, |
994 | 4095, // wbd_ref | 999 | 4095, |
995 | 0, // wbd_sel | 1000 | 0, |
996 | 0, // wbd_alpha | 1001 | 0, |
997 | 1002 | ||
998 | 42598, // agc1_max | 1003 | 42598, |
999 | 16384, // agc1_min | 1004 | 16384, |
1000 | 42598, // agc2_max | 1005 | 42598, |
1001 | 0, // agc2_min | 1006 | 0, |
1002 | 1007 | ||
1003 | 0, // agc1_pt1 | 1008 | 0, |
1004 | 137, // agc1_pt2 | 1009 | 137, |
1005 | 255, // agc1_pt3 | 1010 | 255, |
1006 | 1011 | ||
1007 | 0, // agc1_slope1 | 1012 | 0, |
1008 | 255, // agc1_slope2 | 1013 | 255, |
1009 | 1014 | ||
1010 | 0, // agc2_pt1 | 1015 | 0, |
1011 | 0, // agc2_pt2 | 1016 | 0, |
1012 | 1017 | ||
1013 | 0, // agc2_slope1 | 1018 | 0, |
1014 | 41, // agc2_slope2 | 1019 | 41, |
1015 | 1020 | ||
1016 | 15, // alpha_mant | 1021 | 15, |
1017 | 25, // alpha_exp | 1022 | 25, |
1018 | 1023 | ||
1019 | 28, // beta_mant | 1024 | 28, |
1020 | 48, // beta_exp | 1025 | 48, |
1021 | 1026 | ||
1022 | 0, // perform_agc_softsplit | 1027 | 0, |
1023 | }; | 1028 | }; |
1024 | 1029 | ||
1025 | static struct dibx000_bandwidth_config stk7700p_pll_config = { | 1030 | static struct dibx000_bandwidth_config stk7700p_pll_config = { |
1026 | 60000, 30000, // internal, sampling | 1031 | 60000, 30000, |
1027 | 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass | 1032 | 1, 8, 3, 1, 0, |
1028 | 0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo | 1033 | 0, 0, 1, 1, 0, |
1029 | (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k | 1034 | (3 << 14) | (1 << 12) | (524 << 0), |
1030 | 60258167, // ifreq | 1035 | 60258167, |
1031 | 20452225, // timf | 1036 | 20452225, |
1032 | 30000000, // xtal | 1037 | 30000000, |
1033 | }; | 1038 | }; |
1034 | 1039 | ||
1035 | static struct dib7000m_config stk7700p_dib7000m_config = { | 1040 | static struct dib7000m_config stk7700p_dib7000m_config = { |
@@ -1115,41 +1120,42 @@ static struct dibx000_agc_config dib7070_agc_config = { | |||
1115 | BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, | 1120 | BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, |
1116 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, | 1121 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, |
1117 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ | 1122 | * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ |
1118 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup | 1123 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
1119 | 1124 | | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), | |
1120 | 600, // inv_gain | 1125 | |
1121 | 10, // time_stabiliz | 1126 | 600, |
1122 | 1127 | 10, | |
1123 | 0, // alpha_level | 1128 | |
1124 | 118, // thlock | 1129 | 0, |
1125 | 1130 | 118, | |
1126 | 0, // wbd_inv | 1131 | |
1127 | 3530, // wbd_ref | 1132 | 0, |
1128 | 1, // wbd_sel | 1133 | 3530, |
1129 | 5, // wbd_alpha | 1134 | 1, |
1130 | 1135 | 5, | |
1131 | 65535, // agc1_max | 1136 | |
1132 | 0, // agc1_min | 1137 | 65535, |
1133 | 1138 | 0, | |
1134 | 65535, // agc2_max | 1139 | |
1135 | 0, // agc2_min | 1140 | 65535, |
1136 | 1141 | 0, | |
1137 | 0, // agc1_pt1 | 1142 | |
1138 | 40, // agc1_pt2 | 1143 | 0, |
1139 | 183, // agc1_pt3 | 1144 | 40, |
1140 | 206, // agc1_slope1 | 1145 | 183, |
1141 | 255, // agc1_slope2 | 1146 | 206, |
1142 | 72, // agc2_pt1 | 1147 | 255, |
1143 | 152, // agc2_pt2 | 1148 | 72, |
1144 | 88, // agc2_slope1 | 1149 | 152, |
1145 | 90, // agc2_slope2 | 1150 | 88, |
1146 | 1151 | 90, | |
1147 | 17, // alpha_mant | 1152 | |
1148 | 27, // alpha_exp | 1153 | 17, |
1149 | 23, // beta_mant | 1154 | 27, |
1150 | 51, // beta_exp | 1155 | 23, |
1151 | 1156 | 51, | |
1152 | 0, // perform_agc_softsplit | 1157 | |
1158 | 0, | ||
1153 | }; | 1159 | }; |
1154 | 1160 | ||
1155 | static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) | 1161 | static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) |
@@ -1276,13 +1282,13 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) | |||
1276 | } | 1282 | } |
1277 | 1283 | ||
1278 | static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { | 1284 | static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { |
1279 | 60000, 15000, // internal, sampling | 1285 | 60000, 15000, |
1280 | 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass | 1286 | 1, 20, 3, 1, 0, |
1281 | 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo | 1287 | 0, 0, 1, 1, 2, |
1282 | (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k | 1288 | (3 << 14) | (1 << 12) | (524 << 0), |
1283 | (0 << 25) | 0, // ifreq = 0.000000 MHz | 1289 | (0 << 25) | 0, |
1284 | 20452225, // timf | 1290 | 20452225, |
1285 | 12000000, // xtal_hz | 1291 | 12000000, |
1286 | }; | 1292 | }; |
1287 | 1293 | ||
1288 | static struct dib7000p_config dib7070p_dib7000p_config = { | 1294 | static struct dib7000p_config dib7070p_dib7000p_config = { |
@@ -1476,12 +1482,12 @@ static struct dib8000_config dib807x_dib8000_config[2] = { | |||
1476 | } | 1482 | } |
1477 | }; | 1483 | }; |
1478 | 1484 | ||
1479 | static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff) | 1485 | static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) |
1480 | { | 1486 | { |
1481 | return dib8000_set_gpio(fe, 5, 0, !onoff); | 1487 | return dib8000_set_gpio(fe, 5, 0, !onoff); |
1482 | } | 1488 | } |
1483 | 1489 | ||
1484 | static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff) | 1490 | static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) |
1485 | { | 1491 | { |
1486 | return dib8000_set_gpio(fe, 0, 0, onoff); | 1492 | return dib8000_set_gpio(fe, 0, 0, onoff); |
1487 | } | 1493 | } |
@@ -1494,8 +1500,8 @@ static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { | |||
1494 | static struct dib0070_config dib807x_dib0070_config[2] = { | 1500 | static struct dib0070_config dib807x_dib0070_config[2] = { |
1495 | { | 1501 | { |
1496 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | 1502 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, |
1497 | .reset = dib807x_tuner_reset, | 1503 | .reset = dib80xx_tuner_reset, |
1498 | .sleep = dib807x_tuner_sleep, | 1504 | .sleep = dib80xx_tuner_sleep, |
1499 | .clock_khz = 12000, | 1505 | .clock_khz = 12000, |
1500 | .clock_pad_drive = 4, | 1506 | .clock_pad_drive = 4, |
1501 | .vga_filter = 1, | 1507 | .vga_filter = 1, |
@@ -1508,8 +1514,8 @@ static struct dib0070_config dib807x_dib0070_config[2] = { | |||
1508 | .freq_offset_khz_vhf = -100, | 1514 | .freq_offset_khz_vhf = -100, |
1509 | }, { | 1515 | }, { |
1510 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | 1516 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, |
1511 | .reset = dib807x_tuner_reset, | 1517 | .reset = dib80xx_tuner_reset, |
1512 | .sleep = dib807x_tuner_sleep, | 1518 | .sleep = dib80xx_tuner_sleep, |
1513 | .clock_khz = 12000, | 1519 | .clock_khz = 12000, |
1514 | .clock_pad_drive = 2, | 1520 | .clock_pad_drive = 2, |
1515 | .vga_filter = 1, | 1521 | .vga_filter = 1, |
@@ -1566,12 +1572,14 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) | |||
1566 | return 0; | 1572 | return 0; |
1567 | } | 1573 | } |
1568 | 1574 | ||
1569 | static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) | 1575 | static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, |
1576 | u16 pid, int onoff) | ||
1570 | { | 1577 | { |
1571 | return dib8000_pid_filter(adapter->fe, index, pid, onoff); | 1578 | return dib8000_pid_filter(adapter->fe, index, pid, onoff); |
1572 | } | 1579 | } |
1573 | 1580 | ||
1574 | static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) | 1581 | static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, |
1582 | int onoff) | ||
1575 | { | 1583 | { |
1576 | return dib8000_pid_filter_ctrl(adapter->fe, onoff); | 1584 | return dib8000_pid_filter_ctrl(adapter->fe, onoff); |
1577 | } | 1585 | } |
@@ -1624,7 +1632,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) | |||
1624 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); | 1632 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); |
1625 | 1633 | ||
1626 | /* initialize IC 0 */ | 1634 | /* initialize IC 0 */ |
1627 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80); | 1635 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); |
1628 | 1636 | ||
1629 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, | 1637 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, |
1630 | &dib807x_dib8000_config[0]); | 1638 | &dib807x_dib8000_config[0]); |
@@ -1635,7 +1643,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) | |||
1635 | static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) | 1643 | static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) |
1636 | { | 1644 | { |
1637 | /* initialize IC 1 */ | 1645 | /* initialize IC 1 */ |
1638 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82); | 1646 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); |
1639 | 1647 | ||
1640 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, | 1648 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, |
1641 | &dib807x_dib8000_config[1]); | 1649 | &dib807x_dib8000_config[1]); |
@@ -1643,6 +1651,245 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) | |||
1643 | return adap->fe == NULL ? -ENODEV : 0; | 1651 | return adap->fe == NULL ? -ENODEV : 0; |
1644 | } | 1652 | } |
1645 | 1653 | ||
1654 | /* STK8096GP */ | ||
1655 | struct dibx000_agc_config dib8090_agc_config[2] = { | ||
1656 | { | ||
1657 | BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, | ||
1658 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, | ||
1659 | * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, | ||
1660 | * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ | ||
1661 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | ||
1662 | | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), | ||
1663 | |||
1664 | 787, | ||
1665 | 10, | ||
1666 | |||
1667 | 0, | ||
1668 | 118, | ||
1669 | |||
1670 | 0, | ||
1671 | 3530, | ||
1672 | 1, | ||
1673 | 5, | ||
1674 | |||
1675 | 65535, | ||
1676 | 0, | ||
1677 | |||
1678 | 65535, | ||
1679 | 0, | ||
1680 | |||
1681 | 0, | ||
1682 | 32, | ||
1683 | 114, | ||
1684 | 143, | ||
1685 | 144, | ||
1686 | 114, | ||
1687 | 227, | ||
1688 | 116, | ||
1689 | 117, | ||
1690 | |||
1691 | 28, | ||
1692 | 26, | ||
1693 | 31, | ||
1694 | 51, | ||
1695 | |||
1696 | 0, | ||
1697 | }, | ||
1698 | { | ||
1699 | BAND_CBAND, | ||
1700 | /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, | ||
1701 | * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, | ||
1702 | * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ | ||
1703 | (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | ||
1704 | | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), | ||
1705 | |||
1706 | 787, | ||
1707 | 10, | ||
1708 | |||
1709 | 0, | ||
1710 | 118, | ||
1711 | |||
1712 | 0, | ||
1713 | 3530, | ||
1714 | 1, | ||
1715 | 5, | ||
1716 | |||
1717 | 0, | ||
1718 | 0, | ||
1719 | |||
1720 | 65535, | ||
1721 | 0, | ||
1722 | |||
1723 | 0, | ||
1724 | 32, | ||
1725 | 114, | ||
1726 | 143, | ||
1727 | 144, | ||
1728 | 114, | ||
1729 | 227, | ||
1730 | 116, | ||
1731 | 117, | ||
1732 | |||
1733 | 28, | ||
1734 | 26, | ||
1735 | 31, | ||
1736 | 51, | ||
1737 | |||
1738 | 0, | ||
1739 | } | ||
1740 | }; | ||
1741 | |||
1742 | static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { | ||
1743 | 54000, 13500, | ||
1744 | 1, 18, 3, 1, 0, | ||
1745 | 0, 0, 1, 1, 2, | ||
1746 | (3 << 14) | (1 << 12) | (599 << 0), | ||
1747 | (0 << 25) | 0, | ||
1748 | 20199727, | ||
1749 | 12000000, | ||
1750 | }; | ||
1751 | |||
1752 | static int dib8090_get_adc_power(struct dvb_frontend *fe) | ||
1753 | { | ||
1754 | return dib8000_get_adc_power(fe, 1); | ||
1755 | } | ||
1756 | |||
1757 | static struct dib8000_config dib809x_dib8000_config = { | ||
1758 | .output_mpeg2_in_188_bytes = 1, | ||
1759 | |||
1760 | .agc_config_count = 2, | ||
1761 | .agc = dib8090_agc_config, | ||
1762 | .agc_control = dib0090_dcc_freq, | ||
1763 | .pll = &dib8090_pll_config_12mhz, | ||
1764 | .tuner_is_baseband = 1, | ||
1765 | |||
1766 | .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, | ||
1767 | .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, | ||
1768 | .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, | ||
1769 | |||
1770 | .hostbus_diversity = 1, | ||
1771 | .div_cfg = 0x31, | ||
1772 | .output_mode = OUTMODE_MPEG2_FIFO, | ||
1773 | .drives = 0x2d98, | ||
1774 | .diversity_delay = 144, | ||
1775 | .refclksel = 3, | ||
1776 | }; | ||
1777 | |||
1778 | static struct dib0090_config dib809x_dib0090_config = { | ||
1779 | .io.pll_bypass = 1, | ||
1780 | .io.pll_range = 1, | ||
1781 | .io.pll_prediv = 1, | ||
1782 | .io.pll_loopdiv = 20, | ||
1783 | .io.adc_clock_ratio = 8, | ||
1784 | .io.pll_int_loop_filt = 0, | ||
1785 | .io.clock_khz = 12000, | ||
1786 | .reset = dib80xx_tuner_reset, | ||
1787 | .sleep = dib80xx_tuner_sleep, | ||
1788 | .clkouttobamse = 1, | ||
1789 | .analog_output = 1, | ||
1790 | .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, | ||
1791 | .wbd_vhf_offset = 100, | ||
1792 | .wbd_cband_offset = 450, | ||
1793 | .use_pwm_agc = 1, | ||
1794 | .clkoutdrive = 1, | ||
1795 | .get_adc_power = dib8090_get_adc_power, | ||
1796 | .freq_offset_khz_uhf = 0, | ||
1797 | .freq_offset_khz_vhf = -143, | ||
1798 | }; | ||
1799 | |||
1800 | static int dib8096_set_param_override(struct dvb_frontend *fe, | ||
1801 | struct dvb_frontend_parameters *fep) | ||
1802 | { | ||
1803 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1804 | struct dib0700_adapter_state *state = adap->priv; | ||
1805 | u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); | ||
1806 | u16 offset; | ||
1807 | int ret = 0; | ||
1808 | enum frontend_tune_state tune_state = CT_SHUTDOWN; | ||
1809 | u16 ltgain, rf_gain_limit; | ||
1810 | |||
1811 | ret = state->set_param_save(fe, fep); | ||
1812 | if (ret < 0) | ||
1813 | return ret; | ||
1814 | |||
1815 | switch (band) { | ||
1816 | case BAND_VHF: | ||
1817 | offset = 100; | ||
1818 | break; | ||
1819 | case BAND_UHF: | ||
1820 | offset = 550; | ||
1821 | break; | ||
1822 | default: | ||
1823 | offset = 0; | ||
1824 | break; | ||
1825 | } | ||
1826 | offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; | ||
1827 | dib8000_set_wbd_ref(fe, offset); | ||
1828 | |||
1829 | |||
1830 | if (band == BAND_CBAND) { | ||
1831 | deb_info("tuning in CBAND - soft-AGC startup\n"); | ||
1832 | /* TODO specific wbd target for dib0090 - needed for startup ? */ | ||
1833 | dib0090_set_tune_state(fe, CT_AGC_START); | ||
1834 | do { | ||
1835 | ret = dib0090_gain_control(fe); | ||
1836 | msleep(ret); | ||
1837 | tune_state = dib0090_get_tune_state(fe); | ||
1838 | if (tune_state == CT_AGC_STEP_0) | ||
1839 | dib8000_set_gpio(fe, 6, 0, 1); | ||
1840 | else if (tune_state == CT_AGC_STEP_1) { | ||
1841 | dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); | ||
1842 | if (rf_gain_limit == 0) | ||
1843 | dib8000_set_gpio(fe, 6, 0, 0); | ||
1844 | } | ||
1845 | } while (tune_state < CT_AGC_STOP); | ||
1846 | dib0090_pwm_gain_reset(fe); | ||
1847 | dib8000_pwm_agc_reset(fe); | ||
1848 | dib8000_set_tune_state(fe, CT_DEMOD_START); | ||
1849 | } else { | ||
1850 | deb_info("not tuning in CBAND - standard AGC startup\n"); | ||
1851 | dib0090_pwm_gain_reset(fe); | ||
1852 | } | ||
1853 | |||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1857 | static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) | ||
1858 | { | ||
1859 | struct dib0700_adapter_state *st = adap->priv; | ||
1860 | struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); | ||
1861 | |||
1862 | if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) | ||
1863 | return -ENODEV; | ||
1864 | |||
1865 | st->set_param_save = adap->fe->ops.tuner_ops.set_params; | ||
1866 | adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; | ||
1867 | return 0; | ||
1868 | } | ||
1869 | |||
1870 | static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) | ||
1871 | { | ||
1872 | dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); | ||
1873 | msleep(10); | ||
1874 | dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); | ||
1875 | dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); | ||
1876 | dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); | ||
1877 | |||
1878 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); | ||
1879 | |||
1880 | dib0700_ctrl_clock(adap->dev, 72, 1); | ||
1881 | |||
1882 | msleep(10); | ||
1883 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); | ||
1884 | msleep(10); | ||
1885 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); | ||
1886 | |||
1887 | dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); | ||
1888 | |||
1889 | adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config); | ||
1890 | |||
1891 | return adap->fe == NULL ? -ENODEV : 0; | ||
1892 | } | ||
1646 | 1893 | ||
1647 | /* STK7070PD */ | 1894 | /* STK7070PD */ |
1648 | static struct dib7000p_config stk7070pd_dib7000p_config[2] = { | 1895 | static struct dib7000p_config stk7070pd_dib7000p_config[2] = { |
@@ -1929,14 +2176,17 @@ struct usb_device_id dib0700_usb_id_table[] = { | |||
1929 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, | 2176 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, |
1930 | /* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, | 2177 | /* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, |
1931 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, | 2178 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, |
1932 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, | 2179 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, |
1933 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, | 2180 | { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, |
1934 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, | 2181 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, |
1935 | /* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, | 2182 | /* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, |
1936 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, | 2183 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, |
1937 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, | 2184 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, |
1938 | { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) }, | 2185 | { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) }, |
1939 | { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, | 2186 | { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, |
2187 | /* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, | ||
2188 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, | ||
2189 | { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, | ||
1940 | { 0 } /* Terminating entry */ | 2190 | { 0 } /* Terminating entry */ |
1941 | }; | 2191 | }; |
1942 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | 2192 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); |
@@ -2238,11 +2488,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
2238 | { NULL }, | 2488 | { NULL }, |
2239 | }, | 2489 | }, |
2240 | { "Pinnacle PCTV 73e SE", | 2490 | { "Pinnacle PCTV 73e SE", |
2241 | { &dib0700_usb_id_table[57], NULL }, | 2491 | { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, |
2242 | { NULL }, | 2492 | { NULL }, |
2243 | }, | 2493 | }, |
2244 | { "Pinnacle PCTV 282e", | 2494 | { "Pinnacle PCTV 282e", |
2245 | { &dib0700_usb_id_table[58], NULL }, | 2495 | { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, |
2246 | { NULL }, | 2496 | { NULL }, |
2247 | }, | 2497 | }, |
2248 | }, | 2498 | }, |
@@ -2471,8 +2721,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
2471 | { | 2721 | { |
2472 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | 2722 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
2473 | .pid_filter_count = 32, | 2723 | .pid_filter_count = 32, |
2474 | .pid_filter = stk807x_pid_filter, | 2724 | .pid_filter = stk80xx_pid_filter, |
2475 | .pid_filter_ctrl = stk807x_pid_filter_ctrl, | 2725 | .pid_filter_ctrl = stk80xx_pid_filter_ctrl, |
2476 | .frontend_attach = stk807x_frontend_attach, | 2726 | .frontend_attach = stk807x_frontend_attach, |
2477 | .tuner_attach = dib807x_tuner_attach, | 2727 | .tuner_attach = dib807x_tuner_attach, |
2478 | 2728 | ||
@@ -2510,8 +2760,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
2510 | { | 2760 | { |
2511 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | 2761 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
2512 | .pid_filter_count = 32, | 2762 | .pid_filter_count = 32, |
2513 | .pid_filter = stk807x_pid_filter, | 2763 | .pid_filter = stk80xx_pid_filter, |
2514 | .pid_filter_ctrl = stk807x_pid_filter_ctrl, | 2764 | .pid_filter_ctrl = stk80xx_pid_filter_ctrl, |
2515 | .frontend_attach = stk807xpvr_frontend_attach0, | 2765 | .frontend_attach = stk807xpvr_frontend_attach0, |
2516 | .tuner_attach = dib807x_tuner_attach, | 2766 | .tuner_attach = dib807x_tuner_attach, |
2517 | 2767 | ||
@@ -2523,8 +2773,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
2523 | { | 2773 | { |
2524 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | 2774 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, |
2525 | .pid_filter_count = 32, | 2775 | .pid_filter_count = 32, |
2526 | .pid_filter = stk807x_pid_filter, | 2776 | .pid_filter = stk80xx_pid_filter, |
2527 | .pid_filter_ctrl = stk807x_pid_filter_ctrl, | 2777 | .pid_filter_ctrl = stk80xx_pid_filter_ctrl, |
2528 | .frontend_attach = stk807xpvr_frontend_attach1, | 2778 | .frontend_attach = stk807xpvr_frontend_attach1, |
2529 | .tuner_attach = dib807x_tuner_attach, | 2779 | .tuner_attach = dib807x_tuner_attach, |
2530 | 2780 | ||
@@ -2547,6 +2797,37 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
2547 | .rc_key_map = dib0700_rc_keys, | 2797 | .rc_key_map = dib0700_rc_keys, |
2548 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | 2798 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), |
2549 | .rc_query = dib0700_rc_query | 2799 | .rc_query = dib0700_rc_query |
2800 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
2801 | .num_adapters = 1, | ||
2802 | .adapter = { | ||
2803 | { | ||
2804 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | | ||
2805 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | ||
2806 | .pid_filter_count = 32, | ||
2807 | .pid_filter = stk80xx_pid_filter, | ||
2808 | .pid_filter_ctrl = stk80xx_pid_filter_ctrl, | ||
2809 | .frontend_attach = stk809x_frontend_attach, | ||
2810 | .tuner_attach = dib809x_tuner_attach, | ||
2811 | |||
2812 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
2813 | |||
2814 | .size_of_priv = | ||
2815 | sizeof(struct dib0700_adapter_state), | ||
2816 | }, | ||
2817 | }, | ||
2818 | |||
2819 | .num_device_descs = 1, | ||
2820 | .devices = { | ||
2821 | { "DiBcom STK8096GP reference design", | ||
2822 | { &dib0700_usb_id_table[67], NULL }, | ||
2823 | { NULL }, | ||
2824 | }, | ||
2825 | }, | ||
2826 | |||
2827 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
2828 | .rc_key_map = dib0700_rc_keys, | ||
2829 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
2830 | .rc_query = dib0700_rc_query | ||
2550 | }, | 2831 | }, |
2551 | }; | 2832 | }; |
2552 | 2833 | ||
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index da34979b5337..9143b5631e88 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c | |||
@@ -142,8 +142,13 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num | |||
142 | } else if ((msg[i].flags & I2C_M_RD) == 0) { | 142 | } else if ((msg[i].flags & I2C_M_RD) == 0) { |
143 | if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) | 143 | if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) |
144 | break; | 144 | break; |
145 | } else | 145 | } else if (msg[i].addr != 0x50) { |
146 | break; | 146 | /* 0x50 is the address of the eeprom - we need to protect it |
147 | * from dibusb's bad i2c implementation: reads without | ||
148 | * writing the offset before are forbidden */ | ||
149 | if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) | ||
150 | break; | ||
151 | } | ||
147 | } | 152 | } |
148 | 153 | ||
149 | mutex_unlock(&d->i2c_mutex); | 154 | mutex_unlock(&d->i2c_mutex); |
@@ -243,6 +248,12 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { | |||
243 | 248 | ||
244 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) | 249 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) |
245 | { | 250 | { |
251 | if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && | ||
252 | adap->dev->udev->descriptor.idProduct == | ||
253 | USB_PID_LITEON_DVB_T_WARM) { | ||
254 | msleep(1000); | ||
255 | } | ||
256 | |||
246 | if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || | 257 | if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || |
247 | (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { | 258 | (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { |
248 | if (adap->priv != NULL) { | 259 | if (adap->priv != NULL) { |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f1602d4ace6d..bc3581d58ced 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #define USB_VID_MSI_2 0x1462 | 47 | #define USB_VID_MSI_2 0x1462 |
48 | #define USB_VID_OPERA1 0x695c | 48 | #define USB_VID_OPERA1 0x695c |
49 | #define USB_VID_PINNACLE 0x2304 | 49 | #define USB_VID_PINNACLE 0x2304 |
50 | #define USB_VID_PCTV 0x2013 | ||
50 | #define USB_VID_PIXELVIEW 0x1554 | 51 | #define USB_VID_PIXELVIEW 0x1554 |
51 | #define USB_VID_TECHNOTREND 0x0b48 | 52 | #define USB_VID_TECHNOTREND 0x0b48 |
52 | #define USB_VID_TERRATEC 0x0ccd | 53 | #define USB_VID_TERRATEC 0x0ccd |
@@ -101,6 +102,7 @@ | |||
101 | #define USB_PID_DIBCOM_STK7070PD 0x1ebe | 102 | #define USB_PID_DIBCOM_STK7070PD 0x1ebe |
102 | #define USB_PID_DIBCOM_STK807XP 0x1f90 | 103 | #define USB_PID_DIBCOM_STK807XP 0x1f90 |
103 | #define USB_PID_DIBCOM_STK807XPVR 0x1f98 | 104 | #define USB_PID_DIBCOM_STK807XPVR 0x1f98 |
105 | #define USB_PID_DIBCOM_STK8096GP 0x1fa0 | ||
104 | #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 | 106 | #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 |
105 | #define USB_PID_DIBCOM_STK7770P 0x1e80 | 107 | #define USB_PID_DIBCOM_STK7770P 0x1e80 |
106 | #define USB_PID_DPOSH_M9206_COLD 0x9206 | 108 | #define USB_PID_DPOSH_M9206_COLD 0x9206 |
@@ -211,6 +213,7 @@ | |||
211 | #define USB_PID_PINNACLE_PCTV801E_SE 0x023b | 213 | #define USB_PID_PINNACLE_PCTV801E_SE 0x023b |
212 | #define USB_PID_PINNACLE_PCTV73A 0x0243 | 214 | #define USB_PID_PINNACLE_PCTV73A 0x0243 |
213 | #define USB_PID_PINNACLE_PCTV73ESE 0x0245 | 215 | #define USB_PID_PINNACLE_PCTV73ESE 0x0245 |
216 | #define USB_PID_PINNACLE_PCTV74E 0x0246 | ||
214 | #define USB_PID_PINNACLE_PCTV282E 0x0248 | 217 | #define USB_PID_PINNACLE_PCTV282E 0x0248 |
215 | #define USB_PID_PIXELVIEW_SBTVD 0x5010 | 218 | #define USB_PID_PIXELVIEW_SBTVD 0x5010 |
216 | #define USB_PID_PCTV_200E 0x020e | 219 | #define USB_PID_PCTV_200E 0x020e |
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 5bb9479d154e..64132c0cf80d 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c | |||
@@ -20,6 +20,11 @@ | |||
20 | #include "tda1002x.h" | 20 | #include "tda1002x.h" |
21 | #include "mt312.h" | 21 | #include "mt312.h" |
22 | #include "zl10039.h" | 22 | #include "zl10039.h" |
23 | #include "ds3000.h" | ||
24 | #include "stv0900.h" | ||
25 | #include "stv6110.h" | ||
26 | #include "stb6100.h" | ||
27 | #include "stb6100_proc.h" | ||
23 | 28 | ||
24 | #ifndef USB_PID_DW2102 | 29 | #ifndef USB_PID_DW2102 |
25 | #define USB_PID_DW2102 0x2102 | 30 | #define USB_PID_DW2102 0x2102 |
@@ -37,12 +42,20 @@ | |||
37 | #define USB_PID_CINERGY_S 0x0064 | 42 | #define USB_PID_CINERGY_S 0x0064 |
38 | #endif | 43 | #endif |
39 | 44 | ||
45 | #ifndef USB_PID_TEVII_S630 | ||
46 | #define USB_PID_TEVII_S630 0xd630 | ||
47 | #endif | ||
48 | |||
40 | #ifndef USB_PID_TEVII_S650 | 49 | #ifndef USB_PID_TEVII_S650 |
41 | #define USB_PID_TEVII_S650 0xd650 | 50 | #define USB_PID_TEVII_S650 0xd650 |
42 | #endif | 51 | #endif |
43 | 52 | ||
44 | #ifndef USB_PID_TEVII_S630 | 53 | #ifndef USB_PID_TEVII_S660 |
45 | #define USB_PID_TEVII_S630 0xd630 | 54 | #define USB_PID_TEVII_S660 0xd660 |
55 | #endif | ||
56 | |||
57 | #ifndef USB_PID_PROF_1100 | ||
58 | #define USB_PID_PROF_1100 0xb012 | ||
46 | #endif | 59 | #endif |
47 | 60 | ||
48 | #define DW210X_READ_MSG 0 | 61 | #define DW210X_READ_MSG 0 |
@@ -55,6 +68,10 @@ | |||
55 | #define DW2102_VOLTAGE_CTRL (0x1800) | 68 | #define DW2102_VOLTAGE_CTRL (0x1800) |
56 | #define DW2102_RC_QUERY (0x1a00) | 69 | #define DW2102_RC_QUERY (0x1a00) |
57 | 70 | ||
71 | #define err_str "did not find the firmware file. (%s) " \ | ||
72 | "Please see linux/Documentation/dvb/ for more details " \ | ||
73 | "on firmware-problems." | ||
74 | |||
58 | struct dvb_usb_rc_keys_table { | 75 | struct dvb_usb_rc_keys_table { |
59 | struct dvb_usb_rc_key *rc_keys; | 76 | struct dvb_usb_rc_key *rc_keys; |
60 | int rc_keys_size; | 77 | int rc_keys_size; |
@@ -71,6 +88,12 @@ static int ir_keymap; | |||
71 | module_param_named(keymap, ir_keymap, int, 0644); | 88 | module_param_named(keymap, ir_keymap, int, 0644); |
72 | MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); | 89 | MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); |
73 | 90 | ||
91 | /* demod probe */ | ||
92 | static int demod_probe = 1; | ||
93 | module_param_named(demod, demod_probe, int, 0644); | ||
94 | MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " | ||
95 | "4=stv0903+stb6100(or-able))."); | ||
96 | |||
74 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 97 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
75 | 98 | ||
76 | static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, | 99 | static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, |
@@ -183,7 +206,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
183 | switch (num) { | 206 | switch (num) { |
184 | case 2: | 207 | case 2: |
185 | /* read si2109 register by number */ | 208 | /* read si2109 register by number */ |
186 | buf6[0] = 0xd0; | 209 | buf6[0] = msg[0].addr << 1; |
187 | buf6[1] = msg[0].len; | 210 | buf6[1] = msg[0].len; |
188 | buf6[2] = msg[0].buf[0]; | 211 | buf6[2] = msg[0].buf[0]; |
189 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | 212 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, |
@@ -198,7 +221,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
198 | switch (msg[0].addr) { | 221 | switch (msg[0].addr) { |
199 | case 0x68: | 222 | case 0x68: |
200 | /* write to si2109 register */ | 223 | /* write to si2109 register */ |
201 | buf6[0] = 0xd0; | 224 | buf6[0] = msg[0].addr << 1; |
202 | buf6[1] = msg[0].len; | 225 | buf6[1] = msg[0].len; |
203 | memcpy(buf6 + 2, msg[0].buf, msg[0].len); | 226 | memcpy(buf6 + 2, msg[0].buf, msg[0].len); |
204 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, | 227 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, |
@@ -239,7 +262,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
239 | /* read */ | 262 | /* read */ |
240 | /* first write first register number */ | 263 | /* first write first register number */ |
241 | u8 ibuf[msg[1].len + 2], obuf[3]; | 264 | u8 ibuf[msg[1].len + 2], obuf[3]; |
242 | obuf[0] = 0xd0; | 265 | obuf[0] = msg[0].addr << 1; |
243 | obuf[1] = msg[0].len; | 266 | obuf[1] = msg[0].len; |
244 | obuf[2] = msg[0].buf[0]; | 267 | obuf[2] = msg[0].buf[0]; |
245 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | 268 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, |
@@ -256,7 +279,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
256 | case 0x68: { | 279 | case 0x68: { |
257 | /* write to register */ | 280 | /* write to register */ |
258 | u8 obuf[msg[0].len + 2]; | 281 | u8 obuf[msg[0].len + 2]; |
259 | obuf[0] = 0xd0; | 282 | obuf[0] = msg[0].addr << 1; |
260 | obuf[1] = msg[0].len; | 283 | obuf[1] = msg[0].len; |
261 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | 284 | memcpy(obuf + 2, msg[0].buf, msg[0].len); |
262 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | 285 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, |
@@ -266,7 +289,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
266 | case 0x61: { | 289 | case 0x61: { |
267 | /* write to tuner */ | 290 | /* write to tuner */ |
268 | u8 obuf[msg[0].len + 2]; | 291 | u8 obuf[msg[0].len + 2]; |
269 | obuf[0] = 0xc2; | 292 | obuf[0] = msg[0].addr << 1; |
270 | obuf[1] = msg[0].len; | 293 | obuf[1] = msg[0].len; |
271 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | 294 | memcpy(obuf + 2, msg[0].buf, msg[0].len); |
272 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | 295 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, |
@@ -301,78 +324,78 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i | |||
301 | { | 324 | { |
302 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 325 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
303 | int ret = 0; | 326 | int ret = 0; |
304 | int len, i; | 327 | int len, i, j; |
305 | 328 | ||
306 | if (!d) | 329 | if (!d) |
307 | return -ENODEV; | 330 | return -ENODEV; |
308 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 331 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
309 | return -EAGAIN; | 332 | return -EAGAIN; |
310 | 333 | ||
311 | switch (num) { | 334 | for (j = 0; j < num; j++) { |
312 | case 2: { | 335 | switch (msg[j].addr) { |
313 | /* read */ | ||
314 | /* first write first register number */ | ||
315 | u8 ibuf[msg[1].len + 2], obuf[3]; | ||
316 | obuf[0] = 0xaa; | ||
317 | obuf[1] = msg[0].len; | ||
318 | obuf[2] = msg[0].buf[0]; | ||
319 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
320 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
321 | /* second read registers */ | ||
322 | ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0, | ||
323 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
324 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
325 | |||
326 | break; | ||
327 | } | ||
328 | case 1: | ||
329 | switch (msg[0].addr) { | ||
330 | case 0x55: { | ||
331 | if (msg[0].buf[0] == 0xf7) { | ||
332 | /* firmware */ | ||
333 | /* Write in small blocks */ | ||
334 | u8 obuf[19]; | ||
335 | obuf[0] = 0xaa; | ||
336 | obuf[1] = 0x11; | ||
337 | obuf[2] = 0xf7; | ||
338 | len = msg[0].len - 1; | ||
339 | i = 1; | ||
340 | do { | ||
341 | memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); | ||
342 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
343 | obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); | ||
344 | i += 16; | ||
345 | len -= 16; | ||
346 | } while (len > 0); | ||
347 | } else { | ||
348 | /* write to register */ | ||
349 | u8 obuf[msg[0].len + 2]; | ||
350 | obuf[0] = 0xaa; | ||
351 | obuf[1] = msg[0].len; | ||
352 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
353 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
354 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
355 | } | ||
356 | break; | ||
357 | } | ||
358 | case(DW2102_RC_QUERY): { | 336 | case(DW2102_RC_QUERY): { |
359 | u8 ibuf[2]; | 337 | u8 ibuf[2]; |
360 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | 338 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, |
361 | ibuf, 2, DW210X_READ_MSG); | 339 | ibuf, 2, DW210X_READ_MSG); |
362 | memcpy(msg[0].buf, ibuf , 2); | 340 | memcpy(msg[j].buf, ibuf , 2); |
363 | break; | 341 | break; |
364 | } | 342 | } |
365 | case(DW2102_VOLTAGE_CTRL): { | 343 | case(DW2102_VOLTAGE_CTRL): { |
366 | u8 obuf[2]; | 344 | u8 obuf[2]; |
367 | obuf[0] = 0x30; | 345 | obuf[0] = 0x30; |
368 | obuf[1] = msg[0].buf[0]; | 346 | obuf[1] = msg[j].buf[0]; |
369 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | 347 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
370 | obuf, 2, DW210X_WRITE_MSG); | 348 | obuf, 2, DW210X_WRITE_MSG); |
371 | break; | 349 | break; |
372 | } | 350 | } |
351 | /*case 0x55: cx24116 | ||
352 | case 0x6a: stv0903 | ||
353 | case 0x68: ds3000, stv0903 | ||
354 | case 0x60: ts2020, stv6110, stb6100 */ | ||
355 | default: { | ||
356 | if (msg[j].flags == I2C_M_RD) { | ||
357 | /* read registers */ | ||
358 | u8 ibuf[msg[j].len + 2]; | ||
359 | ret = dw210x_op_rw(d->udev, 0xc3, | ||
360 | (msg[j].addr << 1) + 1, 0, | ||
361 | ibuf, msg[j].len + 2, | ||
362 | DW210X_READ_MSG); | ||
363 | memcpy(msg[j].buf, ibuf + 2, msg[j].len); | ||
364 | mdelay(10); | ||
365 | } else if (((msg[j].buf[0] == 0xb0) && | ||
366 | (msg[j].addr == 0x68)) || | ||
367 | ((msg[j].buf[0] == 0xf7) && | ||
368 | (msg[j].addr == 0x55))) { | ||
369 | /* write firmware */ | ||
370 | u8 obuf[19]; | ||
371 | obuf[0] = msg[j].addr << 1; | ||
372 | obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); | ||
373 | obuf[2] = msg[j].buf[0]; | ||
374 | len = msg[j].len - 1; | ||
375 | i = 1; | ||
376 | do { | ||
377 | memcpy(obuf + 3, msg[j].buf + i, | ||
378 | (len > 16 ? 16 : len)); | ||
379 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
380 | obuf, (len > 16 ? 16 : len) + 3, | ||
381 | DW210X_WRITE_MSG); | ||
382 | i += 16; | ||
383 | len -= 16; | ||
384 | } while (len > 0); | ||
385 | } else { | ||
386 | /* write registers */ | ||
387 | u8 obuf[msg[j].len + 2]; | ||
388 | obuf[0] = msg[j].addr << 1; | ||
389 | obuf[1] = msg[j].len; | ||
390 | memcpy(obuf + 2, msg[j].buf, msg[j].len); | ||
391 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
392 | obuf, msg[j].len + 2, | ||
393 | DW210X_WRITE_MSG); | ||
394 | } | ||
395 | break; | ||
396 | } | ||
373 | } | 397 | } |
374 | 398 | ||
375 | break; | ||
376 | } | 399 | } |
377 | 400 | ||
378 | mutex_unlock(&d->i2c_mutex); | 401 | mutex_unlock(&d->i2c_mutex); |
@@ -442,63 +465,85 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
442 | return num; | 465 | return num; |
443 | } | 466 | } |
444 | 467 | ||
445 | static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 468 | static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
446 | int num) | 469 | int num) |
447 | { | 470 | { |
448 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 471 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
449 | int ret = 0; | 472 | int ret = 0; |
473 | int len, i, j; | ||
450 | 474 | ||
451 | if (!d) | 475 | if (!d) |
452 | return -ENODEV; | 476 | return -ENODEV; |
453 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 477 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
454 | return -EAGAIN; | 478 | return -EAGAIN; |
455 | 479 | ||
456 | switch (num) { | 480 | for (j = 0; j < num; j++) { |
457 | case 2: { /* read */ | 481 | switch (msg[j].addr) { |
458 | u8 ibuf[msg[1].len], obuf[3]; | ||
459 | obuf[0] = msg[1].len; | ||
460 | obuf[1] = (msg[0].addr << 1); | ||
461 | obuf[2] = msg[0].buf[0]; | ||
462 | |||
463 | ret = dw210x_op_rw(d->udev, 0x90, 0, 0, | ||
464 | obuf, 3, DW210X_WRITE_MSG); | ||
465 | msleep(5); | ||
466 | ret = dw210x_op_rw(d->udev, 0x91, 0, 0, | ||
467 | ibuf, msg[1].len, DW210X_READ_MSG); | ||
468 | memcpy(msg[1].buf, ibuf, msg[1].len); | ||
469 | break; | ||
470 | } | ||
471 | case 1: | ||
472 | switch (msg[0].addr) { | ||
473 | case 0x60: | ||
474 | case 0x0e: { | ||
475 | /* write to zl10313, zl10039 register, */ | ||
476 | u8 obuf[msg[0].len + 2]; | ||
477 | obuf[0] = msg[0].len + 1; | ||
478 | obuf[1] = (msg[0].addr << 1); | ||
479 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
480 | ret = dw210x_op_rw(d->udev, 0x80, 0, 0, | ||
481 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
482 | break; | ||
483 | } | ||
484 | case (DW2102_RC_QUERY): { | 482 | case (DW2102_RC_QUERY): { |
485 | u8 ibuf[4]; | 483 | u8 ibuf[4]; |
486 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | 484 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, |
487 | ibuf, 4, DW210X_READ_MSG); | 485 | ibuf, 4, DW210X_READ_MSG); |
488 | msg[0].buf[0] = ibuf[3]; | 486 | memcpy(msg[j].buf, ibuf + 1, 2); |
489 | break; | 487 | break; |
490 | } | 488 | } |
491 | case (DW2102_VOLTAGE_CTRL): { | 489 | case (DW2102_VOLTAGE_CTRL): { |
492 | u8 obuf[2]; | 490 | u8 obuf[2]; |
493 | obuf[0] = 0x03; | 491 | obuf[0] = 3; |
494 | obuf[1] = msg[0].buf[0]; | 492 | obuf[1] = msg[j].buf[0]; |
495 | ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, | 493 | ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, |
496 | obuf, 2, DW210X_WRITE_MSG); | 494 | obuf, 2, DW210X_WRITE_MSG); |
497 | break; | 495 | break; |
498 | } | 496 | } |
497 | /*case 0x55: cx24116 | ||
498 | case 0x6a: stv0903 | ||
499 | case 0x68: ds3000, stv0903 | ||
500 | case 0x60: ts2020, stv6110, stb6100 | ||
501 | case 0xa0: eeprom */ | ||
502 | default: { | ||
503 | if (msg[j].flags == I2C_M_RD) { | ||
504 | /* read registers */ | ||
505 | u8 ibuf[msg[j].len]; | ||
506 | ret = dw210x_op_rw(d->udev, 0x91, 0, 0, | ||
507 | ibuf, msg[j].len, | ||
508 | DW210X_READ_MSG); | ||
509 | memcpy(msg[j].buf, ibuf, msg[j].len); | ||
510 | break; | ||
511 | } else if ((msg[j].buf[0] == 0xb0) && | ||
512 | (msg[j].addr == 0x68)) { | ||
513 | /* write firmware */ | ||
514 | u8 obuf[19]; | ||
515 | obuf[0] = (msg[j].len > 16 ? | ||
516 | 18 : msg[j].len + 1); | ||
517 | obuf[1] = msg[j].addr << 1; | ||
518 | obuf[2] = msg[j].buf[0]; | ||
519 | len = msg[j].len - 1; | ||
520 | i = 1; | ||
521 | do { | ||
522 | memcpy(obuf + 3, msg[j].buf + i, | ||
523 | (len > 16 ? 16 : len)); | ||
524 | ret = dw210x_op_rw(d->udev, 0x80, 0, 0, | ||
525 | obuf, (len > 16 ? 16 : len) + 3, | ||
526 | DW210X_WRITE_MSG); | ||
527 | i += 16; | ||
528 | len -= 16; | ||
529 | } while (len > 0); | ||
530 | } else { | ||
531 | /* write registers */ | ||
532 | u8 obuf[msg[j].len + 2]; | ||
533 | obuf[0] = msg[j].len + 1; | ||
534 | obuf[1] = (msg[j].addr << 1); | ||
535 | memcpy(obuf + 2, msg[j].buf, msg[j].len); | ||
536 | ret = dw210x_op_rw(d->udev, | ||
537 | (num > 1 ? 0x90 : 0x80), 0, 0, | ||
538 | obuf, msg[j].len + 2, | ||
539 | DW210X_WRITE_MSG); | ||
540 | break; | ||
541 | } | ||
542 | break; | ||
543 | } | ||
499 | } | 544 | } |
500 | 545 | ||
501 | break; | 546 | msleep(3); |
502 | } | 547 | } |
503 | 548 | ||
504 | mutex_unlock(&d->i2c_mutex); | 549 | mutex_unlock(&d->i2c_mutex); |
@@ -535,8 +580,8 @@ static struct i2c_algorithm dw3101_i2c_algo = { | |||
535 | .functionality = dw210x_i2c_func, | 580 | .functionality = dw210x_i2c_func, |
536 | }; | 581 | }; |
537 | 582 | ||
538 | static struct i2c_algorithm s630_i2c_algo = { | 583 | static struct i2c_algorithm s6x0_i2c_algo = { |
539 | .master_xfer = s630_i2c_transfer, | 584 | .master_xfer = s6x0_i2c_transfer, |
540 | .functionality = dw210x_i2c_func, | 585 | .functionality = dw210x_i2c_func, |
541 | }; | 586 | }; |
542 | 587 | ||
@@ -564,25 +609,34 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | |||
564 | return 0; | 609 | return 0; |
565 | }; | 610 | }; |
566 | 611 | ||
567 | static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) | 612 | static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) |
568 | { | 613 | { |
569 | int i, ret; | 614 | int i, ret; |
570 | u8 buf[3], eeprom[256], eepromline[16]; | 615 | u8 ibuf[] = { 0 }, obuf[] = { 0 }; |
616 | u8 eeprom[256], eepromline[16]; | ||
617 | struct i2c_msg msg[] = { | ||
618 | { | ||
619 | .addr = 0xa0 >> 1, | ||
620 | .flags = 0, | ||
621 | .buf = obuf, | ||
622 | .len = 1, | ||
623 | }, { | ||
624 | .addr = 0xa0 >> 1, | ||
625 | .flags = I2C_M_RD, | ||
626 | .buf = ibuf, | ||
627 | .len = 1, | ||
628 | } | ||
629 | }; | ||
571 | 630 | ||
572 | for (i = 0; i < 256; i++) { | 631 | for (i = 0; i < 256; i++) { |
573 | buf[0] = 1; | 632 | obuf[0] = i; |
574 | buf[1] = 0xa0; | 633 | ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); |
575 | buf[2] = i; | 634 | if (ret != 2) { |
576 | ret = dw210x_op_rw(d->udev, 0x90, 0, 0, | ||
577 | buf, 3, DW210X_WRITE_MSG); | ||
578 | ret = dw210x_op_rw(d->udev, 0x91, 0, 0, | ||
579 | buf, 1, DW210X_READ_MSG); | ||
580 | if (ret < 0) { | ||
581 | err("read eeprom failed."); | 635 | err("read eeprom failed."); |
582 | return -1; | 636 | return -1; |
583 | } else { | 637 | } else { |
584 | eepromline[i % 16] = buf[0]; | 638 | eepromline[i % 16] = ibuf[0]; |
585 | eeprom[i] = buf[0]; | 639 | eeprom[i] = ibuf[0]; |
586 | } | 640 | } |
587 | 641 | ||
588 | if ((i % 16) == 15) { | 642 | if ((i % 16) == 15) { |
@@ -644,19 +698,104 @@ static struct mt312_config zl313_config = { | |||
644 | .demod_address = 0x0e, | 698 | .demod_address = 0x0e, |
645 | }; | 699 | }; |
646 | 700 | ||
701 | static struct ds3000_config dw2104_ds3000_config = { | ||
702 | .demod_address = 0x68, | ||
703 | }; | ||
704 | |||
705 | static struct stv0900_config dw2104a_stv0900_config = { | ||
706 | .demod_address = 0x6a, | ||
707 | .demod_mode = 0, | ||
708 | .xtal = 27000000, | ||
709 | .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ | ||
710 | .diseqc_mode = 2,/* 2/3 PWM */ | ||
711 | .tun1_maddress = 0,/* 0x60 */ | ||
712 | .tun1_adc = 0,/* 2 Vpp */ | ||
713 | .path1_mode = 3, | ||
714 | }; | ||
715 | |||
716 | static struct stb6100_config dw2104a_stb6100_config = { | ||
717 | .tuner_address = 0x60, | ||
718 | .refclock = 27000000, | ||
719 | }; | ||
720 | |||
721 | static struct stv0900_config dw2104_stv0900_config = { | ||
722 | .demod_address = 0x68, | ||
723 | .demod_mode = 0, | ||
724 | .xtal = 8000000, | ||
725 | .clkmode = 3, | ||
726 | .diseqc_mode = 2, | ||
727 | .tun1_maddress = 0, | ||
728 | .tun1_adc = 1,/* 1 Vpp */ | ||
729 | .path1_mode = 3, | ||
730 | }; | ||
731 | |||
732 | static struct stv6110_config dw2104_stv6110_config = { | ||
733 | .i2c_address = 0x60, | ||
734 | .mclk = 16000000, | ||
735 | .clk_div = 1, | ||
736 | }; | ||
737 | |||
647 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) | 738 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) |
648 | { | 739 | { |
649 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, | 740 | struct dvb_tuner_ops *tuner_ops = NULL; |
650 | &d->dev->i2c_adap)) != NULL) { | 741 | |
742 | if (demod_probe & 4) { | ||
743 | d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, | ||
744 | &d->dev->i2c_adap, 0); | ||
745 | if (d->fe != NULL) { | ||
746 | if (dvb_attach(stb6100_attach, d->fe, | ||
747 | &dw2104a_stb6100_config, | ||
748 | &d->dev->i2c_adap)) { | ||
749 | tuner_ops = &d->fe->ops.tuner_ops; | ||
750 | tuner_ops->set_frequency = stb6100_set_freq; | ||
751 | tuner_ops->get_frequency = stb6100_get_freq; | ||
752 | tuner_ops->set_bandwidth = stb6100_set_bandw; | ||
753 | tuner_ops->get_bandwidth = stb6100_get_bandw; | ||
754 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
755 | info("Attached STV0900+STB6100!\n"); | ||
756 | return 0; | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | |||
761 | if (demod_probe & 2) { | ||
762 | d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, | ||
763 | &d->dev->i2c_adap, 0); | ||
764 | if (d->fe != NULL) { | ||
765 | if (dvb_attach(stv6110_attach, d->fe, | ||
766 | &dw2104_stv6110_config, | ||
767 | &d->dev->i2c_adap)) { | ||
768 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
769 | info("Attached STV0900+STV6110A!\n"); | ||
770 | return 0; | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if (demod_probe & 1) { | ||
776 | d->fe = dvb_attach(cx24116_attach, &dw2104_config, | ||
777 | &d->dev->i2c_adap); | ||
778 | if (d->fe != NULL) { | ||
779 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
780 | info("Attached cx24116!\n"); | ||
781 | return 0; | ||
782 | } | ||
783 | } | ||
784 | |||
785 | d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, | ||
786 | &d->dev->i2c_adap); | ||
787 | if (d->fe != NULL) { | ||
651 | d->fe->ops.set_voltage = dw210x_set_voltage; | 788 | d->fe->ops.set_voltage = dw210x_set_voltage; |
652 | info("Attached cx24116!\n"); | 789 | info("Attached DS3000!\n"); |
653 | return 0; | 790 | return 0; |
654 | } | 791 | } |
792 | |||
655 | return -EIO; | 793 | return -EIO; |
656 | } | 794 | } |
657 | 795 | ||
658 | static struct dvb_usb_device_properties dw2102_properties; | 796 | static struct dvb_usb_device_properties dw2102_properties; |
659 | static struct dvb_usb_device_properties dw2104_properties; | 797 | static struct dvb_usb_device_properties dw2104_properties; |
798 | static struct dvb_usb_device_properties s6x0_properties; | ||
660 | 799 | ||
661 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | 800 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) |
662 | { | 801 | { |
@@ -670,14 +809,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | |||
670 | return 0; | 809 | return 0; |
671 | } | 810 | } |
672 | } | 811 | } |
812 | |||
673 | if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { | 813 | if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { |
674 | /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ | ||
675 | d->fe = dvb_attach(stv0288_attach, &earda_config, | 814 | d->fe = dvb_attach(stv0288_attach, &earda_config, |
676 | &d->dev->i2c_adap); | 815 | &d->dev->i2c_adap); |
677 | if (d->fe != NULL) { | 816 | if (d->fe != NULL) { |
678 | d->fe->ops.set_voltage = dw210x_set_voltage; | 817 | if (dvb_attach(stb6000_attach, d->fe, 0x61, |
679 | info("Attached stv0288!\n"); | 818 | &d->dev->i2c_adap)) { |
680 | return 0; | 819 | d->fe->ops.set_voltage = dw210x_set_voltage; |
820 | info("Attached stv0288!\n"); | ||
821 | return 0; | ||
822 | } | ||
681 | } | 823 | } |
682 | } | 824 | } |
683 | 825 | ||
@@ -705,15 +847,38 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) | |||
705 | return -EIO; | 847 | return -EIO; |
706 | } | 848 | } |
707 | 849 | ||
708 | static int s630_frontend_attach(struct dvb_usb_adapter *d) | 850 | static int s6x0_frontend_attach(struct dvb_usb_adapter *d) |
709 | { | 851 | { |
710 | d->fe = dvb_attach(mt312_attach, &zl313_config, | 852 | d->fe = dvb_attach(mt312_attach, &zl313_config, |
711 | &d->dev->i2c_adap); | 853 | &d->dev->i2c_adap); |
854 | if (d->fe != NULL) { | ||
855 | if (dvb_attach(zl10039_attach, d->fe, 0x60, | ||
856 | &d->dev->i2c_adap)) { | ||
857 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
858 | info("Attached zl100313+zl10039!\n"); | ||
859 | return 0; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | d->fe = dvb_attach(stv0288_attach, &earda_config, | ||
864 | &d->dev->i2c_adap); | ||
865 | if (d->fe != NULL) { | ||
866 | if (dvb_attach(stb6000_attach, d->fe, 0x61, | ||
867 | &d->dev->i2c_adap)) { | ||
868 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
869 | info("Attached stv0288+stb6000!\n"); | ||
870 | return 0; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, | ||
875 | &d->dev->i2c_adap); | ||
712 | if (d->fe != NULL) { | 876 | if (d->fe != NULL) { |
713 | d->fe->ops.set_voltage = dw210x_set_voltage; | 877 | d->fe->ops.set_voltage = dw210x_set_voltage; |
714 | info("Attached zl10313!\n"); | 878 | info("Attached ds3000+ds2020!\n"); |
715 | return 0; | 879 | return 0; |
716 | } | 880 | } |
881 | |||
717 | return -EIO; | 882 | return -EIO; |
718 | } | 883 | } |
719 | 884 | ||
@@ -724,14 +889,6 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | |||
724 | return 0; | 889 | return 0; |
725 | } | 890 | } |
726 | 891 | ||
727 | static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) | ||
728 | { | ||
729 | dvb_attach(stb6000_attach, adap->fe, 0x61, | ||
730 | &adap->dev->i2c_adap); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) | 892 | static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) |
736 | { | 893 | { |
737 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | 894 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, |
@@ -740,14 +897,6 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) | |||
740 | return 0; | 897 | return 0; |
741 | } | 898 | } |
742 | 899 | ||
743 | static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap) | ||
744 | { | ||
745 | dvb_attach(zl10039_attach, adap->fe, 0x60, | ||
746 | &adap->dev->i2c_adap); | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { | 900 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { |
752 | { 0xf80a, KEY_Q }, /*power*/ | 901 | { 0xf80a, KEY_Q }, /*power*/ |
753 | { 0xf80c, KEY_M }, /*mute*/ | 902 | { 0xf80c, KEY_M }, /*mute*/ |
@@ -922,6 +1071,8 @@ static struct usb_device_id dw2102_table[] = { | |||
922 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, | 1071 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, |
923 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, | 1072 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, |
924 | {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, | 1073 | {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, |
1074 | {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, | ||
1075 | {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, | ||
925 | { } | 1076 | { } |
926 | }; | 1077 | }; |
927 | 1078 | ||
@@ -935,15 +1086,13 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
935 | u8 reset; | 1086 | u8 reset; |
936 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; | 1087 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; |
937 | const struct firmware *fw; | 1088 | const struct firmware *fw; |
938 | const char *filename = "dvb-usb-dw2101.fw"; | 1089 | const char *fw_2101 = "dvb-usb-dw2101.fw"; |
939 | 1090 | ||
940 | switch (dev->descriptor.idProduct) { | 1091 | switch (dev->descriptor.idProduct) { |
941 | case 0x2101: | 1092 | case 0x2101: |
942 | ret = request_firmware(&fw, filename, &dev->dev); | 1093 | ret = request_firmware(&fw, fw_2101, &dev->dev); |
943 | if (ret != 0) { | 1094 | if (ret != 0) { |
944 | err("did not find the firmware file. (%s) " | 1095 | err(err_str, fw_2101); |
945 | "Please see linux/Documentation/dvb/ for more details " | ||
946 | "on firmware-problems.", filename); | ||
947 | return ret; | 1096 | return ret; |
948 | } | 1097 | } |
949 | break; | 1098 | break; |
@@ -983,6 +1132,11 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
983 | } | 1132 | } |
984 | /* init registers */ | 1133 | /* init registers */ |
985 | switch (dev->descriptor.idProduct) { | 1134 | switch (dev->descriptor.idProduct) { |
1135 | case USB_PID_PROF_1100: | ||
1136 | s6x0_properties.rc_key_map = tbs_rc_keys; | ||
1137 | s6x0_properties.rc_key_map_size = | ||
1138 | ARRAY_SIZE(tbs_rc_keys); | ||
1139 | break; | ||
986 | case USB_PID_TEVII_S650: | 1140 | case USB_PID_TEVII_S650: |
987 | dw2104_properties.rc_key_map = tevii_rc_keys; | 1141 | dw2104_properties.rc_key_map = tevii_rc_keys; |
988 | dw2104_properties.rc_key_map_size = | 1142 | dw2104_properties.rc_key_map_size = |
@@ -1021,7 +1175,6 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
1021 | DW210X_READ_MSG); | 1175 | DW210X_READ_MSG); |
1022 | if (reset16[2] == 0x11) { | 1176 | if (reset16[2] == 0x11) { |
1023 | dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; | 1177 | dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; |
1024 | dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; | ||
1025 | break; | 1178 | break; |
1026 | } | 1179 | } |
1027 | } | 1180 | } |
@@ -1184,13 +1337,13 @@ static struct dvb_usb_device_properties dw3101_properties = { | |||
1184 | } | 1337 | } |
1185 | }; | 1338 | }; |
1186 | 1339 | ||
1187 | static struct dvb_usb_device_properties s630_properties = { | 1340 | static struct dvb_usb_device_properties s6x0_properties = { |
1188 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | 1341 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
1189 | .usb_ctrl = DEVICE_SPECIFIC, | 1342 | .usb_ctrl = DEVICE_SPECIFIC, |
1190 | .firmware = "dvb-usb-s630.fw", | 1343 | .firmware = "dvb-usb-s630.fw", |
1191 | .no_reconnect = 1, | 1344 | .no_reconnect = 1, |
1192 | 1345 | ||
1193 | .i2c_algo = &s630_i2c_algo, | 1346 | .i2c_algo = &s6x0_i2c_algo, |
1194 | .rc_key_map = tevii_rc_keys, | 1347 | .rc_key_map = tevii_rc_keys, |
1195 | .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys), | 1348 | .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys), |
1196 | .rc_interval = 150, | 1349 | .rc_interval = 150, |
@@ -1199,12 +1352,12 @@ static struct dvb_usb_device_properties s630_properties = { | |||
1199 | .generic_bulk_ctrl_endpoint = 0x81, | 1352 | .generic_bulk_ctrl_endpoint = 0x81, |
1200 | .num_adapters = 1, | 1353 | .num_adapters = 1, |
1201 | .download_firmware = dw2102_load_firmware, | 1354 | .download_firmware = dw2102_load_firmware, |
1202 | .read_mac_address = s630_read_mac_address, | 1355 | .read_mac_address = s6x0_read_mac_address, |
1203 | .adapter = { | 1356 | .adapter = { |
1204 | { | 1357 | { |
1205 | .frontend_attach = s630_frontend_attach, | 1358 | .frontend_attach = s6x0_frontend_attach, |
1206 | .streaming_ctrl = NULL, | 1359 | .streaming_ctrl = NULL, |
1207 | .tuner_attach = s630_zl10039_tuner_attach, | 1360 | .tuner_attach = NULL, |
1208 | .stream = { | 1361 | .stream = { |
1209 | .type = USB_BULK, | 1362 | .type = USB_BULK, |
1210 | .count = 8, | 1363 | .count = 8, |
@@ -1217,12 +1370,20 @@ static struct dvb_usb_device_properties s630_properties = { | |||
1217 | }, | 1370 | }, |
1218 | } | 1371 | } |
1219 | }, | 1372 | }, |
1220 | .num_device_descs = 1, | 1373 | .num_device_descs = 3, |
1221 | .devices = { | 1374 | .devices = { |
1222 | {"TeVii S630 USB", | 1375 | {"TeVii S630 USB", |
1223 | {&dw2102_table[6], NULL}, | 1376 | {&dw2102_table[6], NULL}, |
1224 | {NULL}, | 1377 | {NULL}, |
1225 | }, | 1378 | }, |
1379 | {"Prof 1100 USB ", | ||
1380 | {&dw2102_table[7], NULL}, | ||
1381 | {NULL}, | ||
1382 | }, | ||
1383 | {"TeVii S660 USB", | ||
1384 | {&dw2102_table[8], NULL}, | ||
1385 | {NULL}, | ||
1386 | }, | ||
1226 | } | 1387 | } |
1227 | }; | 1388 | }; |
1228 | 1389 | ||
@@ -1235,10 +1396,10 @@ static int dw2102_probe(struct usb_interface *intf, | |||
1235 | THIS_MODULE, NULL, adapter_nr) || | 1396 | THIS_MODULE, NULL, adapter_nr) || |
1236 | 0 == dvb_usb_device_init(intf, &dw3101_properties, | 1397 | 0 == dvb_usb_device_init(intf, &dw3101_properties, |
1237 | THIS_MODULE, NULL, adapter_nr) || | 1398 | THIS_MODULE, NULL, adapter_nr) || |
1238 | 0 == dvb_usb_device_init(intf, &s630_properties, | 1399 | 0 == dvb_usb_device_init(intf, &s6x0_properties, |
1239 | THIS_MODULE, NULL, adapter_nr)) { | 1400 | THIS_MODULE, NULL, adapter_nr)) |
1240 | return 0; | 1401 | return 0; |
1241 | } | 1402 | |
1242 | return -ENODEV; | 1403 | return -ENODEV; |
1243 | } | 1404 | } |
1244 | 1405 | ||
@@ -1269,6 +1430,7 @@ module_exit(dw2102_module_exit); | |||
1269 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); | 1430 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); |
1270 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," | 1431 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," |
1271 | " DVB-C 3101 USB2.0," | 1432 | " DVB-C 3101 USB2.0," |
1272 | " TeVii S600, S630, S650 USB2.0 devices"); | 1433 | " TeVii S600, S630, S650, S660 USB2.0," |
1434 | " Prof 1100 USB2.0 devices"); | ||
1273 | MODULE_VERSION("0.1"); | 1435 | MODULE_VERSION("0.1"); |
1274 | MODULE_LICENSE("GPL"); | 1436 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c index 9cbbe42ca44b..ebb7b9fd115b 100644 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ b/drivers/media/dvb/dvb-usb/friio-fe.c | |||
@@ -134,11 +134,13 @@ static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) | |||
134 | deb_fe("%s: freq=%d, step=%d\n", __func__, freq, | 134 | deb_fe("%s: freq=%d, step=%d\n", __func__, freq, |
135 | state->frontend.ops.info.frequency_stepsize); | 135 | state->frontend.ops.info.frequency_stepsize); |
136 | /* freq -> oscilator frequency conversion. */ | 136 | /* freq -> oscilator frequency conversion. */ |
137 | /* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */ | 137 | /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ |
138 | /* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */ | ||
139 | /* 1/7MHz for center freq shift */ | ||
140 | f = freq / state->frontend.ops.info.frequency_stepsize; | 138 | f = freq / state->frontend.ops.info.frequency_stepsize; |
141 | f += 400; | 139 | /* add 399[1/7 MHZ] = 57MHz for the IF */ |
140 | f += 399; | ||
141 | /* add center frequency shift if necessary */ | ||
142 | if (f % 7 == 0) | ||
143 | f++; | ||
142 | pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ | 144 | pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ |
143 | pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; | 145 | pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; |
144 | pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; | 146 | pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; |
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 20eadf9318e0..7a7f1b2b681c 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c | |||
@@ -146,8 +146,8 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, | |||
146 | 146 | ||
147 | switch (c->delivery_system) { | 147 | switch (c->delivery_system) { |
148 | case SYS_DVBS: | 148 | case SYS_DVBS: |
149 | /* Only QPSK is supported for DVB-S */ | 149 | /* Allow QPSK and 8PSK (even for DVB-S) */ |
150 | if (c->modulation != QPSK) { | 150 | if (c->modulation != QPSK && c->modulation != PSK_8) { |
151 | deb_fe("%s: unsupported modulation selected (%d)\n", | 151 | deb_fe("%s: unsupported modulation selected (%d)\n", |
152 | __func__, c->modulation); | 152 | __func__, c->modulation); |
153 | return -EOPNOTSUPP; | 153 | return -EOPNOTSUPP; |
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 58aac018f109..a3b8b697349b 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -526,6 +526,15 @@ config DVB_TUNER_DIB0070 | |||
526 | This device is only used inside a SiP called together with a | 526 | This device is only used inside a SiP called together with a |
527 | demodulator for now. | 527 | demodulator for now. |
528 | 528 | ||
529 | config DVB_TUNER_DIB0090 | ||
530 | tristate "DiBcom DiB0090 silicon base-band tuner" | ||
531 | depends on I2C | ||
532 | default m if DVB_FE_CUSTOMISE | ||
533 | help | ||
534 | A driver for the silicon baseband tuner DiB0090 from DiBcom. | ||
535 | This device is only used inside a SiP called together with a | ||
536 | demodulator for now. | ||
537 | |||
529 | comment "SEC control devices for DVB-S" | 538 | comment "SEC control devices for DVB-S" |
530 | depends on DVB_CORE | 539 | depends on DVB_CORE |
531 | 540 | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 823482535d11..47575cc7b699 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -55,6 +55,7 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o | |||
55 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o | 55 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o |
56 | obj-$(CONFIG_DVB_TDA8261) += tda8261.o | 56 | obj-$(CONFIG_DVB_TDA8261) += tda8261.o |
57 | obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o | 57 | obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o |
58 | obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o | ||
58 | obj-$(CONFIG_DVB_TUA6100) += tua6100.o | 59 | obj-$(CONFIG_DVB_TUA6100) += tua6100.o |
59 | obj-$(CONFIG_DVB_S5H1409) += s5h1409.o | 60 | obj-$(CONFIG_DVB_S5H1409) += s5h1409.o |
60 | obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o | 61 | obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o |
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 2dc2723b724a..24268ef2753d 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c | |||
@@ -62,7 +62,7 @@ struct au8522_register_config { | |||
62 | The values are as follows from left to right | 62 | The values are as follows from left to right |
63 | 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" | 63 | 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" |
64 | */ | 64 | */ |
65 | struct au8522_register_config filter_coef[] = { | 65 | static const struct au8522_register_config filter_coef[] = { |
66 | {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, | 66 | {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, |
67 | {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, | 67 | {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, |
68 | {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, | 68 | {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, |
@@ -104,7 +104,7 @@ struct au8522_register_config filter_coef[] = { | |||
104 | 0="SIF" 1="ATVRF/ATVRF13" | 104 | 0="SIF" 1="ATVRF/ATVRF13" |
105 | Note: the "ATVRF/ATVRF13" mode has never been tested | 105 | Note: the "ATVRF/ATVRF13" mode has never been tested |
106 | */ | 106 | */ |
107 | struct au8522_register_config lpfilter_coef[] = { | 107 | static const struct au8522_register_config lpfilter_coef[] = { |
108 | {0x060b, {0x21, 0x0b} }, | 108 | {0x060b, {0x21, 0x0b} }, |
109 | {0x060c, {0xad, 0xad} }, | 109 | {0x060c, {0xad, 0xad} }, |
110 | {0x060d, {0x70, 0xf0} }, | 110 | {0x060d, {0x70, 0xf0} }, |
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 2be17b93e0bd..0d12763603b4 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c | |||
@@ -49,21 +49,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | |||
49 | #define DIB0070_P1G 0x03 | 49 | #define DIB0070_P1G 0x03 |
50 | #define DIB0070S_P1A 0x02 | 50 | #define DIB0070S_P1A 0x02 |
51 | 51 | ||
52 | enum frontend_tune_state { | ||
53 | CT_TUNER_START = 10, | ||
54 | CT_TUNER_STEP_0, | ||
55 | CT_TUNER_STEP_1, | ||
56 | CT_TUNER_STEP_2, | ||
57 | CT_TUNER_STEP_3, | ||
58 | CT_TUNER_STEP_4, | ||
59 | CT_TUNER_STEP_5, | ||
60 | CT_TUNER_STEP_6, | ||
61 | CT_TUNER_STEP_7, | ||
62 | CT_TUNER_STOP, | ||
63 | }; | ||
64 | |||
65 | #define FE_CALLBACK_TIME_NEVER 0xffffffff | ||
66 | |||
67 | struct dib0070_state { | 52 | struct dib0070_state { |
68 | struct i2c_adapter *i2c; | 53 | struct i2c_adapter *i2c; |
69 | struct dvb_frontend *fe; | 54 | struct dvb_frontend *fe; |
@@ -71,10 +56,10 @@ struct dib0070_state { | |||
71 | u16 wbd_ff_offset; | 56 | u16 wbd_ff_offset; |
72 | u8 revision; | 57 | u8 revision; |
73 | 58 | ||
74 | enum frontend_tune_state tune_state; | 59 | enum frontend_tune_state tune_state; |
75 | u32 current_rf; | 60 | u32 current_rf; |
76 | 61 | ||
77 | /* for the captrim binary search */ | 62 | /* for the captrim binary search */ |
78 | s8 step; | 63 | s8 step; |
79 | u16 adc_diff; | 64 | u16 adc_diff; |
80 | 65 | ||
@@ -85,7 +70,7 @@ struct dib0070_state { | |||
85 | const struct dib0070_tuning *current_tune_table_index; | 70 | const struct dib0070_tuning *current_tune_table_index; |
86 | const struct dib0070_lna_match *lna_match; | 71 | const struct dib0070_lna_match *lna_match; |
87 | 72 | ||
88 | u8 wbd_gain_current; | 73 | u8 wbd_gain_current; |
89 | u16 wbd_offset_3_3[2]; | 74 | u16 wbd_offset_3_3[2]; |
90 | }; | 75 | }; |
91 | 76 | ||
@@ -93,8 +78,8 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) | |||
93 | { | 78 | { |
94 | u8 b[2]; | 79 | u8 b[2]; |
95 | struct i2c_msg msg[2] = { | 80 | struct i2c_msg msg[2] = { |
96 | {.addr = state->cfg->i2c_address,.flags = 0,.buf = ®,.len = 1}, | 81 | { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, |
97 | {.addr = state->cfg->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, | 82 | { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, |
98 | }; | 83 | }; |
99 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | 84 | if (i2c_transfer(state->i2c, msg, 2) != 2) { |
100 | printk(KERN_WARNING "DiB0070 I2C read failed\n"); | 85 | printk(KERN_WARNING "DiB0070 I2C read failed\n"); |
@@ -106,7 +91,7 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) | |||
106 | static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) | 91 | static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) |
107 | { | 92 | { |
108 | u8 b[3] = { reg, val >> 8, val & 0xff }; | 93 | u8 b[3] = { reg, val >> 8, val & 0xff }; |
109 | struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 }; | 94 | struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; |
110 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | 95 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { |
111 | printk(KERN_WARNING "DiB0070 I2C write failed\n"); | 96 | printk(KERN_WARNING "DiB0070 I2C write failed\n"); |
112 | return -EREMOTEIO; | 97 | return -EREMOTEIO; |
@@ -124,30 +109,30 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) | |||
124 | 109 | ||
125 | static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | 110 | static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) |
126 | { | 111 | { |
127 | struct dib0070_state *state = fe->tuner_priv; | 112 | struct dib0070_state *state = fe->tuner_priv; |
128 | u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; | 113 | u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; |
129 | 114 | ||
130 | if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000) | 115 | if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) |
131 | tmp |= (0 << 14); | 116 | tmp |= (0 << 14); |
132 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000) | 117 | else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) |
133 | tmp |= (1 << 14); | 118 | tmp |= (1 << 14); |
134 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000) | 119 | else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) |
135 | tmp |= (2 << 14); | 120 | tmp |= (2 << 14); |
136 | else | 121 | else |
137 | tmp |= (3 << 14); | 122 | tmp |= (3 << 14); |
138 | 123 | ||
139 | dib0070_write_reg(state, 0x02, tmp); | 124 | dib0070_write_reg(state, 0x02, tmp); |
140 | 125 | ||
141 | /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ | 126 | /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ |
142 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { | 127 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { |
143 | u16 value = dib0070_read_reg(state, 0x17); | 128 | u16 value = dib0070_read_reg(state, 0x17); |
144 | 129 | ||
145 | dib0070_write_reg(state, 0x17, value & 0xfffc); | 130 | dib0070_write_reg(state, 0x17, value & 0xfffc); |
146 | tmp = dib0070_read_reg(state, 0x01) & 0x01ff; | 131 | tmp = dib0070_read_reg(state, 0x01) & 0x01ff; |
147 | dib0070_write_reg(state, 0x01, tmp | (60 << 9)); | 132 | dib0070_write_reg(state, 0x01, tmp | (60 << 9)); |
148 | 133 | ||
149 | dib0070_write_reg(state, 0x17, value); | 134 | dib0070_write_reg(state, 0x17, value); |
150 | } | 135 | } |
151 | return 0; | 136 | return 0; |
152 | } | 137 | } |
153 | 138 | ||
@@ -160,14 +145,14 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state | |||
160 | if (*tune_state == CT_TUNER_STEP_0) { | 145 | if (*tune_state == CT_TUNER_STEP_0) { |
161 | 146 | ||
162 | dib0070_write_reg(state, 0x0f, 0xed10); | 147 | dib0070_write_reg(state, 0x0f, 0xed10); |
163 | dib0070_write_reg(state, 0x17, 0x0034); | 148 | dib0070_write_reg(state, 0x17, 0x0034); |
164 | 149 | ||
165 | dib0070_write_reg(state, 0x18, 0x0032); | 150 | dib0070_write_reg(state, 0x18, 0x0032); |
166 | state->step = state->captrim = state->fcaptrim = 64; | 151 | state->step = state->captrim = state->fcaptrim = 64; |
167 | state->adc_diff = 3000; | 152 | state->adc_diff = 3000; |
168 | ret = 20; | 153 | ret = 20; |
169 | 154 | ||
170 | *tune_state = CT_TUNER_STEP_1; | 155 | *tune_state = CT_TUNER_STEP_1; |
171 | } else if (*tune_state == CT_TUNER_STEP_1) { | 156 | } else if (*tune_state == CT_TUNER_STEP_1) { |
172 | state->step /= 2; | 157 | state->step /= 2; |
173 | dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); | 158 | dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); |
@@ -178,7 +163,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state | |||
178 | 163 | ||
179 | adc = dib0070_read_reg(state, 0x19); | 164 | adc = dib0070_read_reg(state, 0x19); |
180 | 165 | ||
181 | dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc * (u32) 1800 / (u32) 1024); | 166 | dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); |
182 | 167 | ||
183 | if (adc >= 400) { | 168 | if (adc >= 400) { |
184 | adc -= 400; | 169 | adc -= 400; |
@@ -193,6 +178,8 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state | |||
193 | state->adc_diff = adc; | 178 | state->adc_diff = adc; |
194 | state->fcaptrim = state->captrim; | 179 | state->fcaptrim = state->captrim; |
195 | 180 | ||
181 | |||
182 | |||
196 | } | 183 | } |
197 | state->captrim += (step_sign * state->step); | 184 | state->captrim += (step_sign * state->step); |
198 | 185 | ||
@@ -213,7 +200,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state | |||
213 | static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) | 200 | static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) |
214 | { | 201 | { |
215 | struct dib0070_state *state = fe->tuner_priv; | 202 | struct dib0070_state *state = fe->tuner_priv; |
216 | u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); | 203 | u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); |
217 | dprintk("CTRL_LO5: 0x%x", lo5); | 204 | dprintk("CTRL_LO5: 0x%x", lo5); |
218 | return dib0070_write_reg(state, 0x15, lo5); | 205 | return dib0070_write_reg(state, 0x15, lo5); |
219 | } | 206 | } |
@@ -227,99 +214,99 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) | |||
227 | dib0070_write_reg(state, 0x1a, 0x0000); | 214 | dib0070_write_reg(state, 0x1a, 0x0000); |
228 | } else { | 215 | } else { |
229 | dib0070_write_reg(state, 0x1b, 0x4112); | 216 | dib0070_write_reg(state, 0x1b, 0x4112); |
230 | if (state->cfg->vga_filter != 0) { | 217 | if (state->cfg->vga_filter != 0) { |
231 | dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); | 218 | dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); |
232 | dprintk("vga filter register is set to %x", state->cfg->vga_filter); | 219 | dprintk("vga filter register is set to %x", state->cfg->vga_filter); |
233 | } else | 220 | } else |
234 | dib0070_write_reg(state, 0x1a, 0x0009); | 221 | dib0070_write_reg(state, 0x1a, 0x0009); |
235 | } | 222 | } |
236 | } | 223 | } |
237 | 224 | ||
238 | EXPORT_SYMBOL(dib0070_ctrl_agc_filter); | 225 | EXPORT_SYMBOL(dib0070_ctrl_agc_filter); |
239 | struct dib0070_tuning { | 226 | struct dib0070_tuning { |
240 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | 227 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ |
241 | u8 switch_trim; | 228 | u8 switch_trim; |
242 | u8 vco_band; | 229 | u8 vco_band; |
243 | u8 hfdiv; | 230 | u8 hfdiv; |
244 | u8 vco_multi; | 231 | u8 vco_multi; |
245 | u8 presc; | 232 | u8 presc; |
246 | u8 wbdmux; | 233 | u8 wbdmux; |
247 | u16 tuner_enable; | 234 | u16 tuner_enable; |
248 | }; | 235 | }; |
249 | 236 | ||
250 | struct dib0070_lna_match { | 237 | struct dib0070_lna_match { |
251 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | 238 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ |
252 | u8 lna_band; | 239 | u8 lna_band; |
253 | }; | 240 | }; |
254 | 241 | ||
255 | static const struct dib0070_tuning dib0070s_tuning_table[] = { | 242 | static const struct dib0070_tuning dib0070s_tuning_table[] = { |
256 | {570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800}, /* UHF */ | 243 | { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ |
257 | {700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800}, | 244 | { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, |
258 | {863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800}, | 245 | { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, |
259 | {1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND */ | 246 | { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ |
260 | {1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, | 247 | { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, |
261 | {2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, | 248 | { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, |
262 | {0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000}, /* SBAND */ | 249 | { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ |
263 | }; | 250 | }; |
264 | 251 | ||
265 | static const struct dib0070_tuning dib0070_tuning_table[] = { | 252 | static const struct dib0070_tuning dib0070_tuning_table[] = { |
266 | {115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000}, /* FM below 92MHz cannot be tuned */ | 253 | { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ |
267 | {179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000}, /* VHF */ | 254 | { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ |
268 | {189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000}, | 255 | { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, |
269 | {250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000}, | 256 | { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, |
270 | {569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800}, /* UHF */ | 257 | { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ |
271 | {699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800}, | 258 | { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, |
272 | {863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800}, | 259 | { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, |
273 | {0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND or everything higher than UHF */ | 260 | { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ |
274 | }; | 261 | }; |
275 | 262 | ||
276 | static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { | 263 | static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { |
277 | {180000, 0}, /* VHF */ | 264 | { 180000, 0 }, /* VHF */ |
278 | {188000, 1}, | 265 | { 188000, 1 }, |
279 | {196400, 2}, | 266 | { 196400, 2 }, |
280 | {250000, 3}, | 267 | { 250000, 3 }, |
281 | {550000, 0}, /* UHF */ | 268 | { 550000, 0 }, /* UHF */ |
282 | {590000, 1}, | 269 | { 590000, 1 }, |
283 | {666000, 3}, | 270 | { 666000, 3 }, |
284 | {864000, 5}, | 271 | { 864000, 5 }, |
285 | {1500000, 0}, /* LBAND or everything higher than UHF */ | 272 | { 1500000, 0 }, /* LBAND or everything higher than UHF */ |
286 | {1600000, 1}, | 273 | { 1600000, 1 }, |
287 | {2000000, 3}, | 274 | { 2000000, 3 }, |
288 | {0xffffffff, 7}, | 275 | { 0xffffffff, 7 }, |
289 | }; | 276 | }; |
290 | 277 | ||
291 | static const struct dib0070_lna_match dib0070_lna[] = { | 278 | static const struct dib0070_lna_match dib0070_lna[] = { |
292 | {180000, 0}, /* VHF */ | 279 | { 180000, 0 }, /* VHF */ |
293 | {188000, 1}, | 280 | { 188000, 1 }, |
294 | {196400, 2}, | 281 | { 196400, 2 }, |
295 | {250000, 3}, | 282 | { 250000, 3 }, |
296 | {550000, 2}, /* UHF */ | 283 | { 550000, 2 }, /* UHF */ |
297 | {650000, 3}, | 284 | { 650000, 3 }, |
298 | {750000, 5}, | 285 | { 750000, 5 }, |
299 | {850000, 6}, | 286 | { 850000, 6 }, |
300 | {864000, 7}, | 287 | { 864000, 7 }, |
301 | {1500000, 0}, /* LBAND or everything higher than UHF */ | 288 | { 1500000, 0 }, /* LBAND or everything higher than UHF */ |
302 | {1600000, 1}, | 289 | { 1600000, 1 }, |
303 | {2000000, 3}, | 290 | { 2000000, 3 }, |
304 | {0xffffffff, 7}, | 291 | { 0xffffffff, 7 }, |
305 | }; | 292 | }; |
306 | 293 | ||
307 | #define LPF 100 // define for the loop filter 100kHz by default 16-07-06 | 294 | #define LPF 100 |
308 | static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | 295 | static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) |
309 | { | 296 | { |
310 | struct dib0070_state *state = fe->tuner_priv; | 297 | struct dib0070_state *state = fe->tuner_priv; |
311 | 298 | ||
312 | const struct dib0070_tuning *tune; | 299 | const struct dib0070_tuning *tune; |
313 | const struct dib0070_lna_match *lna_match; | 300 | const struct dib0070_lna_match *lna_match; |
314 | 301 | ||
315 | enum frontend_tune_state *tune_state = &state->tune_state; | 302 | enum frontend_tune_state *tune_state = &state->tune_state; |
316 | int ret = 10; /* 1ms is the default delay most of the time */ | 303 | int ret = 10; /* 1ms is the default delay most of the time */ |
317 | 304 | ||
318 | u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); | 305 | u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); |
319 | u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); | 306 | u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); |
320 | 307 | ||
321 | #ifdef CONFIG_SYS_ISDBT | 308 | #ifdef CONFIG_SYS_ISDBT |
322 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) | 309 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) |
323 | if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) | 310 | if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) |
324 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) | 311 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) |
325 | || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) | 312 | || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) |
@@ -328,172 +315,180 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par | |||
328 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) | 315 | && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) |
329 | freq += 850; | 316 | freq += 850; |
330 | #endif | 317 | #endif |
318 | if (state->current_rf != freq) { | ||
319 | |||
320 | switch (state->revision) { | ||
321 | case DIB0070S_P1A: | ||
322 | tune = dib0070s_tuning_table; | ||
323 | lna_match = dib0070_lna; | ||
324 | break; | ||
325 | default: | ||
326 | tune = dib0070_tuning_table; | ||
327 | if (state->cfg->flip_chip) | ||
328 | lna_match = dib0070_lna_flip_chip; | ||
329 | else | ||
330 | lna_match = dib0070_lna; | ||
331 | break; | ||
332 | } | ||
333 | while (freq > tune->max_freq) /* find the right one */ | ||
334 | tune++; | ||
335 | while (freq > lna_match->max_freq) /* find the right one */ | ||
336 | lna_match++; | ||
337 | |||
338 | state->current_tune_table_index = tune; | ||
339 | state->lna_match = lna_match; | ||
340 | } | ||
341 | |||
342 | if (*tune_state == CT_TUNER_START) { | ||
343 | dprintk("Tuning for Band: %hd (%d kHz)", band, freq); | ||
331 | if (state->current_rf != freq) { | 344 | if (state->current_rf != freq) { |
345 | u8 REFDIV; | ||
346 | u32 FBDiv, Rest, FREF, VCOF_kHz; | ||
347 | u8 Den; | ||
348 | |||
349 | state->current_rf = freq; | ||
350 | state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); | ||
351 | |||
352 | |||
353 | dib0070_write_reg(state, 0x17, 0x30); | ||
354 | |||
355 | |||
356 | VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; | ||
357 | |||
358 | switch (band) { | ||
359 | case BAND_VHF: | ||
360 | REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); | ||
361 | break; | ||
362 | case BAND_FM: | ||
363 | REFDIV = (u8) ((state->cfg->clock_khz) / 1000); | ||
364 | break; | ||
365 | default: | ||
366 | REFDIV = (u8) (state->cfg->clock_khz / 10000); | ||
367 | break; | ||
368 | } | ||
369 | FREF = state->cfg->clock_khz / REFDIV; | ||
370 | |||
371 | |||
332 | 372 | ||
333 | switch (state->revision) { | 373 | switch (state->revision) { |
334 | case DIB0070S_P1A: | 374 | case DIB0070S_P1A: |
335 | tune = dib0070s_tuning_table; | 375 | FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); |
336 | lna_match = dib0070_lna; | 376 | Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; |
337 | break; | 377 | break; |
378 | |||
379 | case DIB0070_P1G: | ||
380 | case DIB0070_P1F: | ||
338 | default: | 381 | default: |
339 | tune = dib0070_tuning_table; | 382 | FBDiv = (freq / (FREF / 2)); |
340 | if (state->cfg->flip_chip) | 383 | Rest = 2 * freq - FBDiv * FREF; |
341 | lna_match = dib0070_lna_flip_chip; | ||
342 | else | ||
343 | lna_match = dib0070_lna; | ||
344 | break; | 384 | break; |
345 | } | 385 | } |
346 | while (freq > tune->max_freq) /* find the right one */ | ||
347 | tune++; | ||
348 | while (freq > lna_match->max_freq) /* find the right one */ | ||
349 | lna_match++; | ||
350 | 386 | ||
351 | state->current_tune_table_index = tune; | 387 | if (Rest < LPF) |
352 | state->lna_match = lna_match; | 388 | Rest = 0; |
353 | } | 389 | else if (Rest < 2 * LPF) |
390 | Rest = 2 * LPF; | ||
391 | else if (Rest > (FREF - LPF)) { | ||
392 | Rest = 0; | ||
393 | FBDiv += 1; | ||
394 | } else if (Rest > (FREF - 2 * LPF)) | ||
395 | Rest = FREF - 2 * LPF; | ||
396 | Rest = (Rest * 6528) / (FREF / 10); | ||
397 | |||
398 | Den = 1; | ||
399 | if (Rest > 0) { | ||
400 | state->lo4 |= (1 << 14) | (1 << 12); | ||
401 | Den = 255; | ||
402 | } | ||
403 | |||
354 | 404 | ||
355 | if (*tune_state == CT_TUNER_START) { | 405 | dib0070_write_reg(state, 0x11, (u16)FBDiv); |
356 | dprintk("Tuning for Band: %hd (%d kHz)", band, freq); | 406 | dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); |
357 | if (state->current_rf != freq) { | 407 | dib0070_write_reg(state, 0x13, (u16) Rest); |
358 | u8 REFDIV; | 408 | |
359 | u32 FBDiv, Rest, FREF, VCOF_kHz; | 409 | if (state->revision == DIB0070S_P1A) { |
360 | u8 Den; | 410 | |
361 | 411 | if (band == BAND_SBAND) { | |
362 | state->current_rf = freq; | 412 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); |
363 | state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); | 413 | dib0070_write_reg(state, 0x1d, 0xFFFF); |
364 | 414 | } else | |
365 | dib0070_write_reg(state, 0x17, 0x30); | 415 | dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); |
366 | |||
367 | VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; | ||
368 | |||
369 | switch (band) { | ||
370 | case BAND_VHF: | ||
371 | REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); | ||
372 | break; | ||
373 | case BAND_FM: | ||
374 | REFDIV = (u8) ((state->cfg->clock_khz) / 1000); | ||
375 | break; | ||
376 | default: | ||
377 | REFDIV = (u8) (state->cfg->clock_khz / 10000); | ||
378 | break; | ||
379 | } | ||
380 | FREF = state->cfg->clock_khz / REFDIV; | ||
381 | |||
382 | switch (state->revision) { | ||
383 | case DIB0070S_P1A: | ||
384 | FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); | ||
385 | Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; | ||
386 | break; | ||
387 | |||
388 | case DIB0070_P1G: | ||
389 | case DIB0070_P1F: | ||
390 | default: | ||
391 | FBDiv = (freq / (FREF / 2)); | ||
392 | Rest = 2 * freq - FBDiv * FREF; | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | if (Rest < LPF) | ||
397 | Rest = 0; | ||
398 | else if (Rest < 2 * LPF) | ||
399 | Rest = 2 * LPF; | ||
400 | else if (Rest > (FREF - LPF)) { | ||
401 | Rest = 0; | ||
402 | FBDiv += 1; | ||
403 | } else if (Rest > (FREF - 2 * LPF)) | ||
404 | Rest = FREF - 2 * LPF; | ||
405 | Rest = (Rest * 6528) / (FREF / 10); | ||
406 | |||
407 | Den = 1; | ||
408 | if (Rest > 0) { | ||
409 | state->lo4 |= (1 << 14) | (1 << 12); | ||
410 | Den = 255; | ||
411 | } | ||
412 | |||
413 | dib0070_write_reg(state, 0x11, (u16) FBDiv); | ||
414 | dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); | ||
415 | dib0070_write_reg(state, 0x13, (u16) Rest); | ||
416 | |||
417 | if (state->revision == DIB0070S_P1A) { | ||
418 | |||
419 | if (band == BAND_SBAND) { | ||
420 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); | ||
421 | dib0070_write_reg(state, 0x1d, 0xFFFF); | ||
422 | } else | ||
423 | dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); | ||
424 | } | ||
425 | |||
426 | dib0070_write_reg(state, 0x20, | ||
427 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); | ||
428 | |||
429 | dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); | ||
430 | dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); | ||
431 | dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); | ||
432 | dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); | ||
433 | dprintk("VCO = %hd", state->current_tune_table_index->vco_band); | ||
434 | dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); | ||
435 | |||
436 | *tune_state = CT_TUNER_STEP_0; | ||
437 | } else { /* we are already tuned to this frequency - the configuration is correct */ | ||
438 | ret = 50; /* wakeup time */ | ||
439 | *tune_state = CT_TUNER_STEP_5; | ||
440 | } | 416 | } |
441 | } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { | ||
442 | 417 | ||
443 | ret = dib0070_captrim(state, tune_state); | 418 | dib0070_write_reg(state, 0x20, |
419 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); | ||
444 | 420 | ||
445 | } else if (*tune_state == CT_TUNER_STEP_4) { | 421 | dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); |
446 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; | 422 | dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); |
447 | if (tmp != NULL) { | 423 | dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); |
448 | while (freq / 1000 > tmp->freq) /* find the right one */ | 424 | dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); |
449 | tmp++; | 425 | dprintk("VCO = %hd", state->current_tune_table_index->vco_band); |
450 | dib0070_write_reg(state, 0x0f, | 426 | dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); |
451 | (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state-> | 427 | |
452 | current_tune_table_index-> | 428 | *tune_state = CT_TUNER_STEP_0; |
453 | wbdmux << 0)); | 429 | } else { /* we are already tuned to this frequency - the configuration is correct */ |
454 | state->wbd_gain_current = tmp->wbd_gain_val; | 430 | ret = 50; /* wakeup time */ |
455 | } else { | 431 | *tune_state = CT_TUNER_STEP_5; |
432 | } | ||
433 | } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { | ||
434 | |||
435 | ret = dib0070_captrim(state, tune_state); | ||
436 | |||
437 | } else if (*tune_state == CT_TUNER_STEP_4) { | ||
438 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; | ||
439 | if (tmp != NULL) { | ||
440 | while (freq/1000 > tmp->freq) /* find the right one */ | ||
441 | tmp++; | ||
442 | dib0070_write_reg(state, 0x0f, | ||
443 | (0 << 15) | (1 << 14) | (3 << 12) | ||
444 | | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | ||
445 | | (state->current_tune_table_index->wbdmux << 0)); | ||
446 | state->wbd_gain_current = tmp->wbd_gain_val; | ||
447 | } else { | ||
456 | dib0070_write_reg(state, 0x0f, | 448 | dib0070_write_reg(state, 0x0f, |
457 | (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> | 449 | (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> |
458 | wbdmux << 0)); | 450 | wbdmux << 0)); |
459 | state->wbd_gain_current = 6; | 451 | state->wbd_gain_current = 6; |
460 | } | 452 | } |
461 | 453 | ||
462 | dib0070_write_reg(state, 0x06, 0x3fff); | 454 | dib0070_write_reg(state, 0x06, 0x3fff); |
463 | dib0070_write_reg(state, 0x07, | 455 | dib0070_write_reg(state, 0x07, |
464 | (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); | 456 | (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); |
465 | dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); | 457 | dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); |
466 | dib0070_write_reg(state, 0x0d, 0x0d80); | 458 | dib0070_write_reg(state, 0x0d, 0x0d80); |
467 | 459 | ||
468 | dib0070_write_reg(state, 0x18, 0x07ff); | ||
469 | dib0070_write_reg(state, 0x17, 0x0033); | ||
470 | 460 | ||
471 | *tune_state = CT_TUNER_STEP_5; | 461 | dib0070_write_reg(state, 0x18, 0x07ff); |
472 | } else if (*tune_state == CT_TUNER_STEP_5) { | 462 | dib0070_write_reg(state, 0x17, 0x0033); |
473 | dib0070_set_bandwidth(fe, ch); | 463 | |
474 | *tune_state = CT_TUNER_STOP; | 464 | |
475 | } else { | 465 | *tune_state = CT_TUNER_STEP_5; |
476 | ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ | 466 | } else if (*tune_state == CT_TUNER_STEP_5) { |
477 | } | 467 | dib0070_set_bandwidth(fe, ch); |
478 | return ret; | 468 | *tune_state = CT_TUNER_STOP; |
469 | } else { | ||
470 | ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ | ||
471 | } | ||
472 | return ret; | ||
479 | } | 473 | } |
480 | 474 | ||
475 | |||
481 | static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | 476 | static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) |
482 | { | 477 | { |
483 | struct dib0070_state *state = fe->tuner_priv; | 478 | struct dib0070_state *state = fe->tuner_priv; |
484 | uint32_t ret; | 479 | uint32_t ret; |
485 | 480 | ||
486 | state->tune_state = CT_TUNER_START; | 481 | state->tune_state = CT_TUNER_START; |
487 | 482 | ||
488 | do { | 483 | do { |
489 | ret = dib0070_tune_digital(fe, p); | 484 | ret = dib0070_tune_digital(fe, p); |
490 | if (ret != FE_CALLBACK_TIME_NEVER) | 485 | if (ret != FE_CALLBACK_TIME_NEVER) |
491 | msleep(ret / 10); | 486 | msleep(ret/10); |
492 | else | 487 | else |
493 | break; | 488 | break; |
494 | } while (state->tune_state != CT_TUNER_STOP); | 489 | } while (state->tune_state != CT_TUNER_STOP); |
495 | 490 | ||
496 | return 0; | 491 | return 0; |
497 | } | 492 | } |
498 | 493 | ||
499 | static int dib0070_wakeup(struct dvb_frontend *fe) | 494 | static int dib0070_wakeup(struct dvb_frontend *fe) |
@@ -512,92 +507,113 @@ static int dib0070_sleep(struct dvb_frontend *fe) | |||
512 | return 0; | 507 | return 0; |
513 | } | 508 | } |
514 | 509 | ||
515 | static const u16 dib0070_p1f_defaults[] = { | 510 | u8 dib0070_get_rf_output(struct dvb_frontend *fe) |
511 | { | ||
512 | struct dib0070_state *state = fe->tuner_priv; | ||
513 | return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; | ||
514 | } | ||
515 | EXPORT_SYMBOL(dib0070_get_rf_output); | ||
516 | |||
517 | int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) | ||
518 | { | ||
519 | struct dib0070_state *state = fe->tuner_priv; | ||
520 | u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; | ||
521 | if (no > 3) | ||
522 | no = 3; | ||
523 | if (no < 1) | ||
524 | no = 1; | ||
525 | return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); | ||
526 | } | ||
527 | EXPORT_SYMBOL(dib0070_set_rf_output); | ||
528 | |||
529 | static const u16 dib0070_p1f_defaults[] = | ||
530 | |||
531 | { | ||
516 | 7, 0x02, | 532 | 7, 0x02, |
517 | 0x0008, | 533 | 0x0008, |
518 | 0x0000, | 534 | 0x0000, |
519 | 0x0000, | 535 | 0x0000, |
520 | 0x0000, | 536 | 0x0000, |
521 | 0x0000, | 537 | 0x0000, |
522 | 0x0002, | 538 | 0x0002, |
523 | 0x0100, | 539 | 0x0100, |
524 | 540 | ||
525 | 3, 0x0d, | 541 | 3, 0x0d, |
526 | 0x0d80, | 542 | 0x0d80, |
527 | 0x0001, | 543 | 0x0001, |
528 | 0x0000, | 544 | 0x0000, |
529 | 545 | ||
530 | 4, 0x11, | 546 | 4, 0x11, |
531 | 0x0000, | 547 | 0x0000, |
532 | 0x0103, | 548 | 0x0103, |
533 | 0x0000, | 549 | 0x0000, |
534 | 0x0000, | 550 | 0x0000, |
535 | 551 | ||
536 | 3, 0x16, | 552 | 3, 0x16, |
537 | 0x0004 | 0x0040, | 553 | 0x0004 | 0x0040, |
538 | 0x0030, | 554 | 0x0030, |
539 | 0x07ff, | 555 | 0x07ff, |
540 | 556 | ||
541 | 6, 0x1b, | 557 | 6, 0x1b, |
542 | 0x4112, | 558 | 0x4112, |
543 | 0xff00, | 559 | 0xff00, |
544 | 0xc07f, | 560 | 0xc07f, |
545 | 0x0000, | 561 | 0x0000, |
546 | 0x0180, | 562 | 0x0180, |
547 | 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, | 563 | 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, |
548 | 564 | ||
549 | 0, | 565 | 0, |
550 | }; | 566 | }; |
551 | 567 | ||
552 | static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) | 568 | static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) |
553 | { | 569 | { |
554 | u16 tuner_en = dib0070_read_reg(state, 0x20); | 570 | u16 tuner_en = dib0070_read_reg(state, 0x20); |
555 | u16 offset; | 571 | u16 offset; |
556 | 572 | ||
557 | dib0070_write_reg(state, 0x18, 0x07ff); | 573 | dib0070_write_reg(state, 0x18, 0x07ff); |
558 | dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); | 574 | dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); |
559 | dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); | 575 | dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); |
560 | msleep(9); | 576 | msleep(9); |
561 | offset = dib0070_read_reg(state, 0x19); | 577 | offset = dib0070_read_reg(state, 0x19); |
562 | dib0070_write_reg(state, 0x20, tuner_en); | 578 | dib0070_write_reg(state, 0x20, tuner_en); |
563 | return offset; | 579 | return offset; |
564 | } | 580 | } |
565 | 581 | ||
566 | static void dib0070_wbd_offset_calibration(struct dib0070_state *state) | 582 | static void dib0070_wbd_offset_calibration(struct dib0070_state *state) |
567 | { | 583 | { |
568 | u8 gain; | 584 | u8 gain; |
569 | for (gain = 6; gain < 8; gain++) { | 585 | for (gain = 6; gain < 8; gain++) { |
570 | state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); | 586 | state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); |
571 | dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]); | 587 | dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); |
572 | } | 588 | } |
573 | } | 589 | } |
574 | 590 | ||
575 | u16 dib0070_wbd_offset(struct dvb_frontend *fe) | 591 | u16 dib0070_wbd_offset(struct dvb_frontend *fe) |
576 | { | 592 | { |
577 | struct dib0070_state *state = fe->tuner_priv; | 593 | struct dib0070_state *state = fe->tuner_priv; |
578 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; | 594 | const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; |
579 | u32 freq = fe->dtv_property_cache.frequency / 1000; | 595 | u32 freq = fe->dtv_property_cache.frequency/1000; |
580 | 596 | ||
581 | if (tmp != NULL) { | 597 | if (tmp != NULL) { |
582 | while (freq / 1000 > tmp->freq) /* find the right one */ | 598 | while (freq/1000 > tmp->freq) /* find the right one */ |
583 | tmp++; | 599 | tmp++; |
584 | state->wbd_gain_current = tmp->wbd_gain_val; | 600 | state->wbd_gain_current = tmp->wbd_gain_val; |
585 | } else | 601 | } else |
586 | state->wbd_gain_current = 6; | 602 | state->wbd_gain_current = 6; |
587 | 603 | ||
588 | return state->wbd_offset_3_3[state->wbd_gain_current - 6]; | 604 | return state->wbd_offset_3_3[state->wbd_gain_current - 6]; |
589 | } | 605 | } |
590 | |||
591 | EXPORT_SYMBOL(dib0070_wbd_offset); | 606 | EXPORT_SYMBOL(dib0070_wbd_offset); |
592 | 607 | ||
593 | #define pgm_read_word(w) (*w) | 608 | #define pgm_read_word(w) (*w) |
594 | static int dib0070_reset(struct dvb_frontend *fe) | 609 | static int dib0070_reset(struct dvb_frontend *fe) |
595 | { | 610 | { |
596 | struct dib0070_state *state = fe->tuner_priv; | 611 | struct dib0070_state *state = fe->tuner_priv; |
597 | u16 l, r, *n; | 612 | u16 l, r, *n; |
598 | 613 | ||
599 | HARD_RESET(state); | 614 | HARD_RESET(state); |
600 | 615 | ||
616 | |||
601 | #ifndef FORCE_SBAND_TUNER | 617 | #ifndef FORCE_SBAND_TUNER |
602 | if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) | 618 | if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) |
603 | state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; | 619 | state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; |
@@ -605,7 +621,7 @@ static int dib0070_reset(struct dvb_frontend *fe) | |||
605 | #else | 621 | #else |
606 | #warning forcing SBAND | 622 | #warning forcing SBAND |
607 | #endif | 623 | #endif |
608 | state->revision = DIB0070S_P1A; | 624 | state->revision = DIB0070S_P1A; |
609 | 625 | ||
610 | /* P1F or not */ | 626 | /* P1F or not */ |
611 | dprintk("Revision: %x", state->revision); | 627 | dprintk("Revision: %x", state->revision); |
@@ -620,7 +636,7 @@ static int dib0070_reset(struct dvb_frontend *fe) | |||
620 | while (l) { | 636 | while (l) { |
621 | r = pgm_read_word(n++); | 637 | r = pgm_read_word(n++); |
622 | do { | 638 | do { |
623 | dib0070_write_reg(state, (u8) r, pgm_read_word(n++)); | 639 | dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); |
624 | r++; | 640 | r++; |
625 | } while (--l); | 641 | } while (--l); |
626 | l = pgm_read_word(n++); | 642 | l = pgm_read_word(n++); |
@@ -633,6 +649,7 @@ static int dib0070_reset(struct dvb_frontend *fe) | |||
633 | else | 649 | else |
634 | r = 2; | 650 | r = 2; |
635 | 651 | ||
652 | |||
636 | r |= state->cfg->osc_buffer_state << 3; | 653 | r |= state->cfg->osc_buffer_state << 3; |
637 | 654 | ||
638 | dib0070_write_reg(state, 0x10, r); | 655 | dib0070_write_reg(state, 0x10, r); |
@@ -643,16 +660,24 @@ static int dib0070_reset(struct dvb_frontend *fe) | |||
643 | dib0070_write_reg(state, 0x02, r | (1 << 5)); | 660 | dib0070_write_reg(state, 0x02, r | (1 << 5)); |
644 | } | 661 | } |
645 | 662 | ||
646 | if (state->revision == DIB0070S_P1A) | 663 | if (state->revision == DIB0070S_P1A) |
647 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); | 664 | dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); |
648 | else | 665 | else |
649 | dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); | 666 | dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); |
650 | 667 | ||
651 | dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); | 668 | dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); |
652 | 669 | ||
653 | dib0070_wbd_offset_calibration(state); | 670 | dib0070_wbd_offset_calibration(state); |
654 | 671 | ||
655 | return 0; | 672 | return 0; |
673 | } | ||
674 | |||
675 | static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
676 | { | ||
677 | struct dib0070_state *state = fe->tuner_priv; | ||
678 | |||
679 | *frequency = 1000 * state->current_rf; | ||
680 | return 0; | ||
656 | } | 681 | } |
657 | 682 | ||
658 | static int dib0070_release(struct dvb_frontend *fe) | 683 | static int dib0070_release(struct dvb_frontend *fe) |
@@ -664,18 +689,18 @@ static int dib0070_release(struct dvb_frontend *fe) | |||
664 | 689 | ||
665 | static const struct dvb_tuner_ops dib0070_ops = { | 690 | static const struct dvb_tuner_ops dib0070_ops = { |
666 | .info = { | 691 | .info = { |
667 | .name = "DiBcom DiB0070", | 692 | .name = "DiBcom DiB0070", |
668 | .frequency_min = 45000000, | 693 | .frequency_min = 45000000, |
669 | .frequency_max = 860000000, | 694 | .frequency_max = 860000000, |
670 | .frequency_step = 1000, | 695 | .frequency_step = 1000, |
671 | }, | 696 | }, |
672 | .release = dib0070_release, | 697 | .release = dib0070_release, |
673 | 698 | ||
674 | .init = dib0070_wakeup, | 699 | .init = dib0070_wakeup, |
675 | .sleep = dib0070_sleep, | 700 | .sleep = dib0070_sleep, |
676 | .set_params = dib0070_tune, | 701 | .set_params = dib0070_tune, |
677 | 702 | ||
678 | // .get_frequency = dib0070_get_frequency, | 703 | .get_frequency = dib0070_get_frequency, |
679 | // .get_bandwidth = dib0070_get_bandwidth | 704 | // .get_bandwidth = dib0070_get_bandwidth |
680 | }; | 705 | }; |
681 | 706 | ||
@@ -687,7 +712,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter | |||
687 | 712 | ||
688 | state->cfg = cfg; | 713 | state->cfg = cfg; |
689 | state->i2c = i2c; | 714 | state->i2c = i2c; |
690 | state->fe = fe; | 715 | state->fe = fe; |
691 | fe->tuner_priv = state; | 716 | fe->tuner_priv = state; |
692 | 717 | ||
693 | if (dib0070_reset(fe) != 0) | 718 | if (dib0070_reset(fe) != 0) |
@@ -699,12 +724,11 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter | |||
699 | fe->tuner_priv = state; | 724 | fe->tuner_priv = state; |
700 | return fe; | 725 | return fe; |
701 | 726 | ||
702 | free_mem: | 727 | free_mem: |
703 | kfree(state); | 728 | kfree(state); |
704 | fe->tuner_priv = NULL; | 729 | fe->tuner_priv = NULL; |
705 | return NULL; | 730 | return NULL; |
706 | } | 731 | } |
707 | |||
708 | EXPORT_SYMBOL(dib0070_attach); | 732 | EXPORT_SYMBOL(dib0070_attach); |
709 | 733 | ||
710 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | 734 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); |
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index eec9e52ffa75..45c31fae3967 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h | |||
@@ -52,6 +52,8 @@ struct dib0070_config { | |||
52 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); | 52 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); |
53 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | 53 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); |
54 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); | 54 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); |
55 | extern u8 dib0070_get_rf_output(struct dvb_frontend *fe); | ||
56 | extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no); | ||
55 | #else | 57 | #else |
56 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) | 58 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) |
57 | { | 59 | { |
@@ -62,7 +64,7 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struc | |||
62 | static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) | 64 | static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) |
63 | { | 65 | { |
64 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 66 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
65 | return -ENODEV; | 67 | return 0; |
66 | } | 68 | } |
67 | 69 | ||
68 | static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) | 70 | static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) |
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c new file mode 100644 index 000000000000..614552709a6f --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.c | |||
@@ -0,0 +1,1522 @@ | |||
1 | /* | ||
2 | * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. | ||
3 | * | ||
4 | * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of the | ||
9 | * License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | * | ||
22 | * This code is more or less generated from another driver, please | ||
23 | * excuse some codingstyle oddities. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/i2c.h> | ||
29 | |||
30 | #include "dvb_frontend.h" | ||
31 | |||
32 | #include "dib0090.h" | ||
33 | #include "dibx000_common.h" | ||
34 | |||
35 | static int debug; | ||
36 | module_param(debug, int, 0644); | ||
37 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | ||
38 | |||
39 | #define dprintk(args...) do { \ | ||
40 | if (debug) { \ | ||
41 | printk(KERN_DEBUG "DiB0090: "); \ | ||
42 | printk(args); \ | ||
43 | printk("\n"); \ | ||
44 | } \ | ||
45 | } while (0) | ||
46 | |||
47 | #define CONFIG_SYS_ISDBT | ||
48 | #define CONFIG_BAND_CBAND | ||
49 | #define CONFIG_BAND_VHF | ||
50 | #define CONFIG_BAND_UHF | ||
51 | #define CONFIG_DIB0090_USE_PWM_AGC | ||
52 | |||
53 | #define EN_LNA0 0x8000 | ||
54 | #define EN_LNA1 0x4000 | ||
55 | #define EN_LNA2 0x2000 | ||
56 | #define EN_LNA3 0x1000 | ||
57 | #define EN_MIX0 0x0800 | ||
58 | #define EN_MIX1 0x0400 | ||
59 | #define EN_MIX2 0x0200 | ||
60 | #define EN_MIX3 0x0100 | ||
61 | #define EN_IQADC 0x0040 | ||
62 | #define EN_PLL 0x0020 | ||
63 | #define EN_TX 0x0010 | ||
64 | #define EN_BB 0x0008 | ||
65 | #define EN_LO 0x0004 | ||
66 | #define EN_BIAS 0x0001 | ||
67 | |||
68 | #define EN_IQANA 0x0002 | ||
69 | #define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ | ||
70 | #define EN_CRYSTAL 0x0002 | ||
71 | |||
72 | #define EN_UHF 0x22E9 | ||
73 | #define EN_VHF 0x44E9 | ||
74 | #define EN_LBD 0x11E9 | ||
75 | #define EN_SBD 0x44E9 | ||
76 | #define EN_CAB 0x88E9 | ||
77 | |||
78 | #define pgm_read_word(w) (*w) | ||
79 | |||
80 | struct dc_calibration; | ||
81 | |||
82 | struct dib0090_tuning { | ||
83 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
84 | u8 switch_trim; | ||
85 | u8 lna_tune; | ||
86 | u8 lna_bias; | ||
87 | u16 v2i; | ||
88 | u16 mix; | ||
89 | u16 load; | ||
90 | u16 tuner_enable; | ||
91 | }; | ||
92 | |||
93 | struct dib0090_pll { | ||
94 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
95 | u8 vco_band; | ||
96 | u8 hfdiv_code; | ||
97 | u8 hfdiv; | ||
98 | u8 topresc; | ||
99 | }; | ||
100 | |||
101 | struct dib0090_state { | ||
102 | struct i2c_adapter *i2c; | ||
103 | struct dvb_frontend *fe; | ||
104 | const struct dib0090_config *config; | ||
105 | |||
106 | u8 current_band; | ||
107 | u16 revision; | ||
108 | enum frontend_tune_state tune_state; | ||
109 | u32 current_rf; | ||
110 | |||
111 | u16 wbd_offset; | ||
112 | s16 wbd_target; /* in dB */ | ||
113 | |||
114 | s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ | ||
115 | s16 current_gain; /* keeps the currently programmed gain */ | ||
116 | u8 agc_step; /* new binary search */ | ||
117 | |||
118 | u16 gain[2]; /* for channel monitoring */ | ||
119 | |||
120 | const u16 *rf_ramp; | ||
121 | const u16 *bb_ramp; | ||
122 | |||
123 | /* for the software AGC ramps */ | ||
124 | u16 bb_1_def; | ||
125 | u16 rf_lt_def; | ||
126 | u16 gain_reg[4]; | ||
127 | |||
128 | /* for the captrim/dc-offset search */ | ||
129 | s8 step; | ||
130 | s16 adc_diff; | ||
131 | s16 min_adc_diff; | ||
132 | |||
133 | s8 captrim; | ||
134 | s8 fcaptrim; | ||
135 | |||
136 | const struct dc_calibration *dc; | ||
137 | u16 bb6, bb7; | ||
138 | |||
139 | const struct dib0090_tuning *current_tune_table_index; | ||
140 | const struct dib0090_pll *current_pll_table_index; | ||
141 | |||
142 | u8 tuner_is_tuned; | ||
143 | u8 agc_freeze; | ||
144 | |||
145 | u8 reset; | ||
146 | }; | ||
147 | |||
148 | static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) | ||
149 | { | ||
150 | u8 b[2]; | ||
151 | struct i2c_msg msg[2] = { | ||
152 | {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, | ||
153 | {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, | ||
154 | }; | ||
155 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
156 | printk(KERN_WARNING "DiB0090 I2C read failed\n"); | ||
157 | return 0; | ||
158 | } | ||
159 | return (b[0] << 8) | b[1]; | ||
160 | } | ||
161 | |||
162 | static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) | ||
163 | { | ||
164 | u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; | ||
165 | struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; | ||
166 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
167 | printk(KERN_WARNING "DiB0090 I2C write failed\n"); | ||
168 | return -EREMOTEIO; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) | ||
174 | #define ADC_TARGET -220 | ||
175 | #define GAIN_ALPHA 5 | ||
176 | #define WBD_ALPHA 6 | ||
177 | #define LPF 100 | ||
178 | static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) | ||
179 | { | ||
180 | do { | ||
181 | dib0090_write_reg(state, r++, *b++); | ||
182 | } while (--c); | ||
183 | } | ||
184 | |||
185 | static u16 dib0090_identify(struct dvb_frontend *fe) | ||
186 | { | ||
187 | struct dib0090_state *state = fe->tuner_priv; | ||
188 | u16 v; | ||
189 | |||
190 | v = dib0090_read_reg(state, 0x1a); | ||
191 | |||
192 | #ifdef FIRMWARE_FIREFLY | ||
193 | /* pll is not locked locked */ | ||
194 | if (!(v & 0x800)) | ||
195 | dprintk("FE%d : Identification : pll is not yet locked", fe->id); | ||
196 | #endif | ||
197 | |||
198 | /* without PLL lock info */ | ||
199 | v &= 0x3ff; | ||
200 | dprintk("P/V: %04x:", v); | ||
201 | |||
202 | if ((v >> 8) & 0xf) | ||
203 | dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf); | ||
204 | else | ||
205 | return 0xff; | ||
206 | |||
207 | v &= 0xff; | ||
208 | if (((v >> 5) & 0x7) == 0x1) | ||
209 | dprintk("FE%d : MP001 : 9090/8096", fe->id); | ||
210 | else if (((v >> 5) & 0x7) == 0x4) | ||
211 | dprintk("FE%d : MP005 : Single Sband", fe->id); | ||
212 | else if (((v >> 5) & 0x7) == 0x6) | ||
213 | dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id); | ||
214 | else if (((v >> 5) & 0x7) == 0x7) | ||
215 | dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id); | ||
216 | else | ||
217 | return 0xff; | ||
218 | |||
219 | /* revision only */ | ||
220 | if ((v & 0x1f) == 0x3) | ||
221 | dprintk("FE%d : P1-D/E/F detected", fe->id); | ||
222 | else if ((v & 0x1f) == 0x1) | ||
223 | dprintk("FE%d : P1C detected", fe->id); | ||
224 | else if ((v & 0x1f) == 0x0) { | ||
225 | #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT | ||
226 | dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id); | ||
227 | dib0090_p1b_register(fe); | ||
228 | #else | ||
229 | dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id); | ||
230 | return 0xff; | ||
231 | #endif | ||
232 | } | ||
233 | |||
234 | return v; | ||
235 | } | ||
236 | |||
237 | static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) | ||
238 | { | ||
239 | struct dib0090_state *state = fe->tuner_priv; | ||
240 | |||
241 | HARD_RESET(state); | ||
242 | |||
243 | dib0090_write_reg(state, 0x24, EN_PLL); | ||
244 | dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ | ||
245 | |||
246 | /* adcClkOutRatio=8->7, release reset */ | ||
247 | dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); | ||
248 | if (cfg->clkoutdrive != 0) | ||
249 | dib0090_write_reg(state, 0x23, | ||
250 | (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg-> | ||
251 | clkouttobamse | ||
252 | << 4) | (0 | ||
253 | << | ||
254 | 2) | ||
255 | | (0)); | ||
256 | else | ||
257 | dib0090_write_reg(state, 0x23, | ||
258 | (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg-> | ||
259 | clkouttobamse << 4) | (0 | ||
260 | << | ||
261 | 2) | ||
262 | | (0)); | ||
263 | |||
264 | /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */ | ||
265 | dib0090_write_reg(state, 0x21, | ||
266 | (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)); | ||
267 | |||
268 | } | ||
269 | |||
270 | static int dib0090_wakeup(struct dvb_frontend *fe) | ||
271 | { | ||
272 | struct dib0090_state *state = fe->tuner_priv; | ||
273 | if (state->config->sleep) | ||
274 | state->config->sleep(fe, 0); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int dib0090_sleep(struct dvb_frontend *fe) | ||
279 | { | ||
280 | struct dib0090_state *state = fe->tuner_priv; | ||
281 | if (state->config->sleep) | ||
282 | state->config->sleep(fe, 1); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) | ||
287 | { | ||
288 | struct dib0090_state *state = fe->tuner_priv; | ||
289 | if (fast) | ||
290 | dib0090_write_reg(state, 0x04, 0); | ||
291 | else | ||
292 | dib0090_write_reg(state, 0x04, 1); | ||
293 | } | ||
294 | EXPORT_SYMBOL(dib0090_dcc_freq); | ||
295 | |||
296 | static const u16 rf_ramp_pwm_cband[] = { | ||
297 | 0, /* max RF gain in 10th of dB */ | ||
298 | 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
299 | 0, /* ramp_max = maximum X used on the ramp */ | ||
300 | (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ | ||
301 | (0 << 10) | 0, /* 0x2d, LNA 1 */ | ||
302 | (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ | ||
303 | (0 << 10) | 0, /* 0x2f, LNA 2 */ | ||
304 | (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ | ||
305 | (0 << 10) | 0, /* 0x31, LNA 3 */ | ||
306 | (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ | ||
307 | (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ | ||
308 | }; | ||
309 | |||
310 | static const u16 rf_ramp_vhf[] = { | ||
311 | 412, /* max RF gain in 10th of dB */ | ||
312 | 132, 307, 127, /* LNA1, 13.2dB */ | ||
313 | 105, 412, 255, /* LNA2, 10.5dB */ | ||
314 | 50, 50, 127, /* LNA3, 5dB */ | ||
315 | 125, 175, 127, /* LNA4, 12.5dB */ | ||
316 | 0, 0, 127, /* CBAND, 0dB */ | ||
317 | }; | ||
318 | |||
319 | static const u16 rf_ramp_uhf[] = { | ||
320 | 412, /* max RF gain in 10th of dB */ | ||
321 | 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ | ||
322 | 105, 412, 255, /* LNA2 : 10.5 dB */ | ||
323 | 50, 50, 127, /* LNA3 : 5.0 dB */ | ||
324 | 125, 175, 127, /* LNA4 : 12.5 dB */ | ||
325 | 0, 0, 127, /* CBAND : 0.0 dB */ | ||
326 | }; | ||
327 | |||
328 | static const u16 rf_ramp_cband[] = { | ||
329 | 332, /* max RF gain in 10th of dB */ | ||
330 | 132, 252, 127, /* LNA1, dB */ | ||
331 | 80, 332, 255, /* LNA2, dB */ | ||
332 | 0, 0, 127, /* LNA3, dB */ | ||
333 | 0, 0, 127, /* LNA4, dB */ | ||
334 | 120, 120, 127, /* LT1 CBAND */ | ||
335 | }; | ||
336 | |||
337 | static const u16 rf_ramp_pwm_vhf[] = { | ||
338 | 404, /* max RF gain in 10th of dB */ | ||
339 | 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
340 | 1011, /* ramp_max = maximum X used on the ramp */ | ||
341 | (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ | ||
342 | (0 << 10) | 756, /* 0x2d, LNA 1 */ | ||
343 | (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ | ||
344 | (0 << 10) | 1011, /* 0x2f, LNA 2 */ | ||
345 | (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ | ||
346 | (0 << 10) | 417, /* 0x31, LNA 3 */ | ||
347 | (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ | ||
348 | (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ | ||
349 | }; | ||
350 | |||
351 | static const u16 rf_ramp_pwm_uhf[] = { | ||
352 | 404, /* max RF gain in 10th of dB */ | ||
353 | 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
354 | 1011, /* ramp_max = maximum X used on the ramp */ | ||
355 | (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ | ||
356 | (0 << 10) | 756, /* 0x2d, LNA 1 */ | ||
357 | (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ | ||
358 | (0 << 10) | 1011, /* 0x2f, LNA 2 */ | ||
359 | (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ | ||
360 | (0 << 10) | 127, /* 0x31, LNA 3 */ | ||
361 | (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ | ||
362 | (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ | ||
363 | }; | ||
364 | |||
365 | static const u16 bb_ramp_boost[] = { | ||
366 | 550, /* max BB gain in 10th of dB */ | ||
367 | 260, 260, 26, /* BB1, 26dB */ | ||
368 | 290, 550, 29, /* BB2, 29dB */ | ||
369 | }; | ||
370 | |||
371 | static const u16 bb_ramp_pwm_normal[] = { | ||
372 | 500, /* max RF gain in 10th of dB */ | ||
373 | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ | ||
374 | 400, | ||
375 | (2 << 9) | 0, /* 0x35 = 21dB */ | ||
376 | (0 << 9) | 168, /* 0x36 */ | ||
377 | (2 << 9) | 168, /* 0x37 = 29dB */ | ||
378 | (0 << 9) | 400, /* 0x38 */ | ||
379 | }; | ||
380 | |||
381 | struct slope { | ||
382 | int16_t range; | ||
383 | int16_t slope; | ||
384 | }; | ||
385 | static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) | ||
386 | { | ||
387 | u8 i; | ||
388 | u16 rest; | ||
389 | u16 ret = 0; | ||
390 | for (i = 0; i < num; i++) { | ||
391 | if (val > slopes[i].range) | ||
392 | rest = slopes[i].range; | ||
393 | else | ||
394 | rest = val; | ||
395 | ret += (rest * slopes[i].slope) / slopes[i].range; | ||
396 | val -= rest; | ||
397 | } | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static const struct slope dib0090_wbd_slopes[3] = { | ||
402 | {66, 120}, /* -64,-52: offset - 65 */ | ||
403 | {600, 170}, /* -52,-35: 65 - 665 */ | ||
404 | {170, 250}, /* -45,-10: 665 - 835 */ | ||
405 | }; | ||
406 | |||
407 | static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) | ||
408 | { | ||
409 | wbd &= 0x3ff; | ||
410 | if (wbd < state->wbd_offset) | ||
411 | wbd = 0; | ||
412 | else | ||
413 | wbd -= state->wbd_offset; | ||
414 | /* -64dB is the floor */ | ||
415 | return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); | ||
416 | } | ||
417 | |||
418 | static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) | ||
419 | { | ||
420 | u16 offset = 250; | ||
421 | |||
422 | /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ | ||
423 | |||
424 | if (state->current_band == BAND_VHF) | ||
425 | offset = 650; | ||
426 | #ifndef FIRMWARE_FIREFLY | ||
427 | if (state->current_band == BAND_VHF) | ||
428 | offset = state->config->wbd_vhf_offset; | ||
429 | if (state->current_band == BAND_CBAND) | ||
430 | offset = state->config->wbd_cband_offset; | ||
431 | #endif | ||
432 | |||
433 | state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); | ||
434 | dprintk("wbd-target: %d dB", (u32) state->wbd_target); | ||
435 | } | ||
436 | |||
437 | static const int gain_reg_addr[4] = { | ||
438 | 0x08, 0x0a, 0x0f, 0x01 | ||
439 | }; | ||
440 | |||
441 | static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) | ||
442 | { | ||
443 | u16 rf, bb, ref; | ||
444 | u16 i, v, gain_reg[4] = { 0 }, gain; | ||
445 | const u16 *g; | ||
446 | |||
447 | if (top_delta < -511) | ||
448 | top_delta = -511; | ||
449 | if (top_delta > 511) | ||
450 | top_delta = 511; | ||
451 | |||
452 | if (force) { | ||
453 | top_delta *= (1 << WBD_ALPHA); | ||
454 | gain_delta *= (1 << GAIN_ALPHA); | ||
455 | } | ||
456 | |||
457 | if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ | ||
458 | state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; | ||
459 | else | ||
460 | state->rf_gain_limit += top_delta; | ||
461 | |||
462 | if (state->rf_gain_limit < 0) /*underflow */ | ||
463 | state->rf_gain_limit = 0; | ||
464 | |||
465 | /* use gain as a temporary variable and correct current_gain */ | ||
466 | gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; | ||
467 | if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ | ||
468 | state->current_gain = gain; | ||
469 | else | ||
470 | state->current_gain += gain_delta; | ||
471 | /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ | ||
472 | if (state->current_gain < 0) | ||
473 | state->current_gain = 0; | ||
474 | |||
475 | /* now split total gain to rf and bb gain */ | ||
476 | gain = state->current_gain >> GAIN_ALPHA; | ||
477 | |||
478 | /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ | ||
479 | if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { | ||
480 | rf = state->rf_gain_limit >> WBD_ALPHA; | ||
481 | bb = gain - rf; | ||
482 | if (bb > state->bb_ramp[0]) | ||
483 | bb = state->bb_ramp[0]; | ||
484 | } else { /* high signal level -> all gains put on RF */ | ||
485 | rf = gain; | ||
486 | bb = 0; | ||
487 | } | ||
488 | |||
489 | state->gain[0] = rf; | ||
490 | state->gain[1] = bb; | ||
491 | |||
492 | /* software ramp */ | ||
493 | /* Start with RF gains */ | ||
494 | g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ | ||
495 | ref = rf; | ||
496 | for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ | ||
497 | if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ | ||
498 | v = 0; /* force the gain to write for the current amp to be null */ | ||
499 | else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ | ||
500 | v = g[2]; /* force this amp to be full gain */ | ||
501 | else /* compute the value to set to this amp because we are somewhere in his range */ | ||
502 | v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; | ||
503 | |||
504 | if (i == 0) /* LNA 1 reg mapping */ | ||
505 | gain_reg[0] = v; | ||
506 | else if (i == 1) /* LNA 2 reg mapping */ | ||
507 | gain_reg[0] |= v << 7; | ||
508 | else if (i == 2) /* LNA 3 reg mapping */ | ||
509 | gain_reg[1] = v; | ||
510 | else if (i == 3) /* LNA 4 reg mapping */ | ||
511 | gain_reg[1] |= v << 7; | ||
512 | else if (i == 4) /* CBAND LNA reg mapping */ | ||
513 | gain_reg[2] = v | state->rf_lt_def; | ||
514 | else if (i == 5) /* BB gain 1 reg mapping */ | ||
515 | gain_reg[3] = v << 3; | ||
516 | else if (i == 6) /* BB gain 2 reg mapping */ | ||
517 | gain_reg[3] |= v << 8; | ||
518 | |||
519 | g += 3; /* go to next gain bloc */ | ||
520 | |||
521 | /* When RF is finished, start with BB */ | ||
522 | if (i == 4) { | ||
523 | g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ | ||
524 | ref = bb; | ||
525 | } | ||
526 | } | ||
527 | gain_reg[3] |= state->bb_1_def; | ||
528 | gain_reg[3] |= ((bb % 10) * 100) / 125; | ||
529 | |||
530 | #ifdef DEBUG_AGC | ||
531 | dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, | ||
532 | gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); | ||
533 | #endif | ||
534 | |||
535 | /* Write the amplifier regs */ | ||
536 | for (i = 0; i < 4; i++) { | ||
537 | v = gain_reg[i]; | ||
538 | if (force || state->gain_reg[i] != v) { | ||
539 | state->gain_reg[i] = v; | ||
540 | dib0090_write_reg(state, gain_reg_addr[i], v); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | static void dib0090_set_boost(struct dib0090_state *state, int onoff) | ||
546 | { | ||
547 | state->bb_1_def &= 0xdfff; | ||
548 | state->bb_1_def |= onoff << 13; | ||
549 | } | ||
550 | |||
551 | static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) | ||
552 | { | ||
553 | state->rf_ramp = cfg; | ||
554 | } | ||
555 | |||
556 | static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) | ||
557 | { | ||
558 | state->rf_ramp = cfg; | ||
559 | |||
560 | dib0090_write_reg(state, 0x2a, 0xffff); | ||
561 | |||
562 | dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); | ||
563 | |||
564 | dib0090_write_regs(state, 0x2c, cfg + 3, 6); | ||
565 | dib0090_write_regs(state, 0x3e, cfg + 9, 2); | ||
566 | } | ||
567 | |||
568 | static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) | ||
569 | { | ||
570 | state->bb_ramp = cfg; | ||
571 | dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ | ||
572 | } | ||
573 | |||
574 | static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) | ||
575 | { | ||
576 | state->bb_ramp = cfg; | ||
577 | |||
578 | dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ | ||
579 | |||
580 | dib0090_write_reg(state, 0x33, 0xffff); | ||
581 | dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); | ||
582 | dib0090_write_regs(state, 0x35, cfg + 3, 4); | ||
583 | } | ||
584 | |||
585 | void dib0090_pwm_gain_reset(struct dvb_frontend *fe) | ||
586 | { | ||
587 | struct dib0090_state *state = fe->tuner_priv; | ||
588 | /* reset the AGC */ | ||
589 | |||
590 | if (state->config->use_pwm_agc) { | ||
591 | #ifdef CONFIG_BAND_SBAND | ||
592 | if (state->current_band == BAND_SBAND) { | ||
593 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); | ||
594 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); | ||
595 | } else | ||
596 | #endif | ||
597 | #ifdef CONFIG_BAND_CBAND | ||
598 | if (state->current_band == BAND_CBAND) { | ||
599 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); | ||
600 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
601 | } else | ||
602 | #endif | ||
603 | #ifdef CONFIG_BAND_VHF | ||
604 | if (state->current_band == BAND_VHF) { | ||
605 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); | ||
606 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
607 | } else | ||
608 | #endif | ||
609 | { | ||
610 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); | ||
611 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
612 | } | ||
613 | |||
614 | if (state->rf_ramp[0] != 0) | ||
615 | dib0090_write_reg(state, 0x32, (3 << 11)); | ||
616 | else | ||
617 | dib0090_write_reg(state, 0x32, (0 << 11)); | ||
618 | |||
619 | dib0090_write_reg(state, 0x39, (1 << 10)); | ||
620 | } | ||
621 | } | ||
622 | EXPORT_SYMBOL(dib0090_pwm_gain_reset); | ||
623 | |||
624 | int dib0090_gain_control(struct dvb_frontend *fe) | ||
625 | { | ||
626 | struct dib0090_state *state = fe->tuner_priv; | ||
627 | enum frontend_tune_state *tune_state = &state->tune_state; | ||
628 | int ret = 10; | ||
629 | |||
630 | u16 wbd_val = 0; | ||
631 | u8 apply_gain_immediatly = 1; | ||
632 | s16 wbd_error = 0, adc_error = 0; | ||
633 | |||
634 | if (*tune_state == CT_AGC_START) { | ||
635 | state->agc_freeze = 0; | ||
636 | dib0090_write_reg(state, 0x04, 0x0); | ||
637 | |||
638 | #ifdef CONFIG_BAND_SBAND | ||
639 | if (state->current_band == BAND_SBAND) { | ||
640 | dib0090_set_rframp(state, rf_ramp_sband); | ||
641 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
642 | } else | ||
643 | #endif | ||
644 | #ifdef CONFIG_BAND_VHF | ||
645 | if (state->current_band == BAND_VHF) { | ||
646 | dib0090_set_rframp(state, rf_ramp_vhf); | ||
647 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
648 | } else | ||
649 | #endif | ||
650 | #ifdef CONFIG_BAND_CBAND | ||
651 | if (state->current_band == BAND_CBAND) { | ||
652 | dib0090_set_rframp(state, rf_ramp_cband); | ||
653 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
654 | } else | ||
655 | #endif | ||
656 | { | ||
657 | dib0090_set_rframp(state, rf_ramp_uhf); | ||
658 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
659 | } | ||
660 | |||
661 | dib0090_write_reg(state, 0x32, 0); | ||
662 | dib0090_write_reg(state, 0x39, 0); | ||
663 | |||
664 | dib0090_wbd_target(state, state->current_rf); | ||
665 | |||
666 | state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; | ||
667 | state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; | ||
668 | |||
669 | *tune_state = CT_AGC_STEP_0; | ||
670 | } else if (!state->agc_freeze) { | ||
671 | s16 wbd; | ||
672 | |||
673 | int adc; | ||
674 | wbd_val = dib0090_read_reg(state, 0x1d); | ||
675 | |||
676 | /* read and calc the wbd power */ | ||
677 | wbd = dib0090_wbd_to_db(state, wbd_val); | ||
678 | wbd_error = state->wbd_target - wbd; | ||
679 | |||
680 | if (*tune_state == CT_AGC_STEP_0) { | ||
681 | if (wbd_error < 0 && state->rf_gain_limit > 0) { | ||
682 | #ifdef CONFIG_BAND_CBAND | ||
683 | /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ | ||
684 | u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; | ||
685 | if (state->current_band == BAND_CBAND && ltg2) { | ||
686 | ltg2 >>= 1; | ||
687 | state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ | ||
688 | } | ||
689 | #endif | ||
690 | } else { | ||
691 | state->agc_step = 0; | ||
692 | *tune_state = CT_AGC_STEP_1; | ||
693 | } | ||
694 | } else { | ||
695 | /* calc the adc power */ | ||
696 | adc = state->config->get_adc_power(fe); | ||
697 | adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ | ||
698 | |||
699 | adc_error = (s16) (((s32) ADC_TARGET) - adc); | ||
700 | #ifdef CONFIG_STANDARD_DAB | ||
701 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) | ||
702 | adc_error += 130; | ||
703 | #endif | ||
704 | #ifdef CONFIG_STANDARD_DVBT | ||
705 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && | ||
706 | (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) | ||
707 | adc_error += 60; | ||
708 | #endif | ||
709 | #ifdef CONFIG_SYS_ISDBT | ||
710 | if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > | ||
711 | 0) | ||
712 | && | ||
713 | ((state->fe->dtv_property_cache.layer[0].modulation == | ||
714 | QAM_64) | ||
715 | || (state->fe->dtv_property_cache.layer[0]. | ||
716 | modulation == QAM_16))) | ||
717 | || | ||
718 | ((state->fe->dtv_property_cache.layer[1].segment_count > | ||
719 | 0) | ||
720 | && | ||
721 | ((state->fe->dtv_property_cache.layer[1].modulation == | ||
722 | QAM_64) | ||
723 | || (state->fe->dtv_property_cache.layer[1]. | ||
724 | modulation == QAM_16))) | ||
725 | || | ||
726 | ((state->fe->dtv_property_cache.layer[2].segment_count > | ||
727 | 0) | ||
728 | && | ||
729 | ((state->fe->dtv_property_cache.layer[2].modulation == | ||
730 | QAM_64) | ||
731 | || (state->fe->dtv_property_cache.layer[2]. | ||
732 | modulation == QAM_16))) | ||
733 | ) | ||
734 | ) | ||
735 | adc_error += 60; | ||
736 | #endif | ||
737 | |||
738 | if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ | ||
739 | if (ABS(adc_error) < 50 || state->agc_step++ > 5) { | ||
740 | |||
741 | #ifdef CONFIG_STANDARD_DAB | ||
742 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { | ||
743 | dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ | ||
744 | dib0090_write_reg(state, 0x04, 0x0); | ||
745 | } else | ||
746 | #endif | ||
747 | { | ||
748 | dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); | ||
749 | dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ | ||
750 | } | ||
751 | |||
752 | *tune_state = CT_AGC_STOP; | ||
753 | } | ||
754 | } else { | ||
755 | /* everything higher than or equal to CT_AGC_STOP means tracking */ | ||
756 | ret = 100; /* 10ms interval */ | ||
757 | apply_gain_immediatly = 0; | ||
758 | } | ||
759 | } | ||
760 | #ifdef DEBUG_AGC | ||
761 | dprintk | ||
762 | ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", | ||
763 | (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, | ||
764 | (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); | ||
765 | #endif | ||
766 | } | ||
767 | |||
768 | /* apply gain */ | ||
769 | if (!state->agc_freeze) | ||
770 | dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); | ||
771 | return ret; | ||
772 | } | ||
773 | EXPORT_SYMBOL(dib0090_gain_control); | ||
774 | |||
775 | void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) | ||
776 | { | ||
777 | struct dib0090_state *state = fe->tuner_priv; | ||
778 | if (rf) | ||
779 | *rf = state->gain[0]; | ||
780 | if (bb) | ||
781 | *bb = state->gain[1]; | ||
782 | if (rf_gain_limit) | ||
783 | *rf_gain_limit = state->rf_gain_limit; | ||
784 | if (rflt) | ||
785 | *rflt = (state->rf_lt_def >> 10) & 0x7; | ||
786 | } | ||
787 | EXPORT_SYMBOL(dib0090_get_current_gain); | ||
788 | |||
789 | u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) | ||
790 | { | ||
791 | struct dib0090_state *st = tuner->tuner_priv; | ||
792 | return st->wbd_offset; | ||
793 | } | ||
794 | EXPORT_SYMBOL(dib0090_get_wbd_offset); | ||
795 | |||
796 | static const u16 dib0090_defaults[] = { | ||
797 | |||
798 | 25, 0x01, | ||
799 | 0x0000, | ||
800 | 0x99a0, | ||
801 | 0x6008, | ||
802 | 0x0000, | ||
803 | 0x8acb, | ||
804 | 0x0000, | ||
805 | 0x0405, | ||
806 | 0x0000, | ||
807 | 0x0000, | ||
808 | 0x0000, | ||
809 | 0xb802, | ||
810 | 0x0300, | ||
811 | 0x2d12, | ||
812 | 0xbac0, | ||
813 | 0x7c00, | ||
814 | 0xdbb9, | ||
815 | 0x0954, | ||
816 | 0x0743, | ||
817 | 0x8000, | ||
818 | 0x0001, | ||
819 | 0x0040, | ||
820 | 0x0100, | ||
821 | 0x0000, | ||
822 | 0xe910, | ||
823 | 0x149e, | ||
824 | |||
825 | 1, 0x1c, | ||
826 | 0xff2d, | ||
827 | |||
828 | 1, 0x39, | ||
829 | 0x0000, | ||
830 | |||
831 | 1, 0x1b, | ||
832 | EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL, | ||
833 | 2, 0x1e, | ||
834 | 0x07FF, | ||
835 | 0x0007, | ||
836 | |||
837 | 1, 0x24, | ||
838 | EN_UHF | EN_CRYSTAL, | ||
839 | |||
840 | 2, 0x3c, | ||
841 | 0x3ff, | ||
842 | 0x111, | ||
843 | 0 | ||
844 | }; | ||
845 | |||
846 | static int dib0090_reset(struct dvb_frontend *fe) | ||
847 | { | ||
848 | struct dib0090_state *state = fe->tuner_priv; | ||
849 | u16 l, r, *n; | ||
850 | |||
851 | dib0090_reset_digital(fe, state->config); | ||
852 | state->revision = dib0090_identify(fe); | ||
853 | |||
854 | /* Revision definition */ | ||
855 | if (state->revision == 0xff) | ||
856 | return -EINVAL; | ||
857 | #ifdef EFUSE | ||
858 | else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */ | ||
859 | dib0090_set_EFUSE(state); | ||
860 | #endif | ||
861 | |||
862 | #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT | ||
863 | if (!(state->revision & 0x1)) /* it is P1B - reset is already done */ | ||
864 | return 0; | ||
865 | #endif | ||
866 | |||
867 | /* Upload the default values */ | ||
868 | n = (u16 *) dib0090_defaults; | ||
869 | l = pgm_read_word(n++); | ||
870 | while (l) { | ||
871 | r = pgm_read_word(n++); | ||
872 | do { | ||
873 | /* DEBUG_TUNER */ | ||
874 | /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */ | ||
875 | dib0090_write_reg(state, r, pgm_read_word(n++)); | ||
876 | r++; | ||
877 | } while (--l); | ||
878 | l = pgm_read_word(n++); | ||
879 | } | ||
880 | |||
881 | /* Congigure in function of the crystal */ | ||
882 | if (state->config->io.clock_khz >= 24000) | ||
883 | l = 1; | ||
884 | else | ||
885 | l = 2; | ||
886 | dib0090_write_reg(state, 0x14, l); | ||
887 | dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); | ||
888 | |||
889 | state->reset = 3; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | #define steps(u) (((u) > 15) ? ((u)-16) : (u)) | ||
895 | #define INTERN_WAIT 10 | ||
896 | static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
897 | { | ||
898 | int ret = INTERN_WAIT * 10; | ||
899 | |||
900 | switch (*tune_state) { | ||
901 | case CT_TUNER_STEP_2: | ||
902 | /* Turns to positive */ | ||
903 | dib0090_write_reg(state, 0x1f, 0x7); | ||
904 | *tune_state = CT_TUNER_STEP_3; | ||
905 | break; | ||
906 | |||
907 | case CT_TUNER_STEP_3: | ||
908 | state->adc_diff = dib0090_read_reg(state, 0x1d); | ||
909 | |||
910 | /* Turns to negative */ | ||
911 | dib0090_write_reg(state, 0x1f, 0x4); | ||
912 | *tune_state = CT_TUNER_STEP_4; | ||
913 | break; | ||
914 | |||
915 | case CT_TUNER_STEP_4: | ||
916 | state->adc_diff -= dib0090_read_reg(state, 0x1d); | ||
917 | *tune_state = CT_TUNER_STEP_5; | ||
918 | ret = 0; | ||
919 | break; | ||
920 | |||
921 | default: | ||
922 | break; | ||
923 | } | ||
924 | |||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | struct dc_calibration { | ||
929 | uint8_t addr; | ||
930 | uint8_t offset; | ||
931 | uint8_t pga:1; | ||
932 | uint16_t bb1; | ||
933 | uint8_t i:1; | ||
934 | }; | ||
935 | |||
936 | static const struct dc_calibration dc_table[] = { | ||
937 | /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ | ||
938 | {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, | ||
939 | {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, | ||
940 | /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ | ||
941 | {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, | ||
942 | {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, | ||
943 | {0}, | ||
944 | }; | ||
945 | |||
946 | static void dib0090_set_trim(struct dib0090_state *state) | ||
947 | { | ||
948 | u16 *val; | ||
949 | |||
950 | if (state->dc->addr == 0x07) | ||
951 | val = &state->bb7; | ||
952 | else | ||
953 | val = &state->bb6; | ||
954 | |||
955 | *val &= ~(0x1f << state->dc->offset); | ||
956 | *val |= state->step << state->dc->offset; | ||
957 | |||
958 | dib0090_write_reg(state, state->dc->addr, *val); | ||
959 | } | ||
960 | |||
961 | static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
962 | { | ||
963 | int ret = 0; | ||
964 | |||
965 | switch (*tune_state) { | ||
966 | |||
967 | case CT_TUNER_START: | ||
968 | /* init */ | ||
969 | dprintk("Internal DC calibration"); | ||
970 | |||
971 | /* the LNA is off */ | ||
972 | dib0090_write_reg(state, 0x24, 0x02ed); | ||
973 | |||
974 | /* force vcm2 = 0.8V */ | ||
975 | state->bb6 = 0; | ||
976 | state->bb7 = 0x040d; | ||
977 | |||
978 | state->dc = dc_table; | ||
979 | |||
980 | *tune_state = CT_TUNER_STEP_0; | ||
981 | |||
982 | /* fall through */ | ||
983 | |||
984 | case CT_TUNER_STEP_0: | ||
985 | dib0090_write_reg(state, 0x01, state->dc->bb1); | ||
986 | dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); | ||
987 | |||
988 | state->step = 0; | ||
989 | |||
990 | state->min_adc_diff = 1023; | ||
991 | |||
992 | *tune_state = CT_TUNER_STEP_1; | ||
993 | ret = 50; | ||
994 | break; | ||
995 | |||
996 | case CT_TUNER_STEP_1: | ||
997 | dib0090_set_trim(state); | ||
998 | |||
999 | *tune_state = CT_TUNER_STEP_2; | ||
1000 | break; | ||
1001 | |||
1002 | case CT_TUNER_STEP_2: | ||
1003 | case CT_TUNER_STEP_3: | ||
1004 | case CT_TUNER_STEP_4: | ||
1005 | ret = dib0090_get_offset(state, tune_state); | ||
1006 | break; | ||
1007 | |||
1008 | case CT_TUNER_STEP_5: /* found an offset */ | ||
1009 | dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step); | ||
1010 | |||
1011 | /* first turn for this frequency */ | ||
1012 | if (state->step == 0) { | ||
1013 | if (state->dc->pga && state->adc_diff < 0) | ||
1014 | state->step = 0x10; | ||
1015 | if (state->dc->pga == 0 && state->adc_diff > 0) | ||
1016 | state->step = 0x10; | ||
1017 | } | ||
1018 | |||
1019 | state->adc_diff = ABS(state->adc_diff); | ||
1020 | |||
1021 | if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */ | ||
1022 | state->step++; | ||
1023 | state->min_adc_diff = state->adc_diff; | ||
1024 | *tune_state = CT_TUNER_STEP_1; | ||
1025 | } else { | ||
1026 | |||
1027 | /* the minimum was what we have seen in the step before */ | ||
1028 | state->step--; | ||
1029 | dib0090_set_trim(state); | ||
1030 | |||
1031 | dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff, | ||
1032 | state->step); | ||
1033 | |||
1034 | state->dc++; | ||
1035 | if (state->dc->addr == 0) /* done */ | ||
1036 | *tune_state = CT_TUNER_STEP_6; | ||
1037 | else | ||
1038 | *tune_state = CT_TUNER_STEP_0; | ||
1039 | |||
1040 | } | ||
1041 | break; | ||
1042 | |||
1043 | case CT_TUNER_STEP_6: | ||
1044 | dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); | ||
1045 | dib0090_write_reg(state, 0x1f, 0x7); | ||
1046 | *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ | ||
1047 | state->reset &= ~0x1; | ||
1048 | default: | ||
1049 | break; | ||
1050 | } | ||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
1055 | { | ||
1056 | switch (*tune_state) { | ||
1057 | case CT_TUNER_START: | ||
1058 | /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */ | ||
1059 | dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10)); | ||
1060 | dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff); | ||
1061 | |||
1062 | *tune_state = CT_TUNER_STEP_0; | ||
1063 | return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ | ||
1064 | case CT_TUNER_STEP_0: | ||
1065 | state->wbd_offset = dib0090_read_reg(state, 0x1d); | ||
1066 | dprintk("WBD calibration offset = %d", state->wbd_offset); | ||
1067 | |||
1068 | *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ | ||
1069 | state->reset &= ~0x2; | ||
1070 | break; | ||
1071 | default: | ||
1072 | break; | ||
1073 | } | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static void dib0090_set_bandwidth(struct dib0090_state *state) | ||
1078 | { | ||
1079 | u16 tmp; | ||
1080 | |||
1081 | if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) | ||
1082 | tmp = (3 << 14); | ||
1083 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) | ||
1084 | tmp = (2 << 14); | ||
1085 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) | ||
1086 | tmp = (1 << 14); | ||
1087 | else | ||
1088 | tmp = (0 << 14); | ||
1089 | |||
1090 | state->bb_1_def &= 0x3fff; | ||
1091 | state->bb_1_def |= tmp; | ||
1092 | |||
1093 | dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ | ||
1094 | } | ||
1095 | |||
1096 | static const struct dib0090_pll dib0090_pll_table[] = { | ||
1097 | #ifdef CONFIG_BAND_CBAND | ||
1098 | {56000, 0, 9, 48, 6}, | ||
1099 | {70000, 1, 9, 48, 6}, | ||
1100 | {87000, 0, 8, 32, 4}, | ||
1101 | {105000, 1, 8, 32, 4}, | ||
1102 | {115000, 0, 7, 24, 6}, | ||
1103 | {140000, 1, 7, 24, 6}, | ||
1104 | {170000, 0, 6, 16, 4}, | ||
1105 | #endif | ||
1106 | #ifdef CONFIG_BAND_VHF | ||
1107 | {200000, 1, 6, 16, 4}, | ||
1108 | {230000, 0, 5, 12, 6}, | ||
1109 | {280000, 1, 5, 12, 6}, | ||
1110 | {340000, 0, 4, 8, 4}, | ||
1111 | {380000, 1, 4, 8, 4}, | ||
1112 | {450000, 0, 3, 6, 6}, | ||
1113 | #endif | ||
1114 | #ifdef CONFIG_BAND_UHF | ||
1115 | {580000, 1, 3, 6, 6}, | ||
1116 | {700000, 0, 2, 4, 4}, | ||
1117 | {860000, 1, 2, 4, 4}, | ||
1118 | #endif | ||
1119 | #ifdef CONFIG_BAND_LBAND | ||
1120 | {1800000, 1, 0, 2, 4}, | ||
1121 | #endif | ||
1122 | #ifdef CONFIG_BAND_SBAND | ||
1123 | {2900000, 0, 14, 1, 4}, | ||
1124 | #endif | ||
1125 | }; | ||
1126 | |||
1127 | static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { | ||
1128 | |||
1129 | #ifdef CONFIG_BAND_CBAND | ||
1130 | {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1131 | {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1132 | {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1133 | #endif | ||
1134 | #ifdef CONFIG_BAND_UHF | ||
1135 | {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1136 | {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1137 | {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1138 | {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1139 | {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1140 | {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1141 | #endif | ||
1142 | #ifdef CONFIG_BAND_LBAND | ||
1143 | {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1144 | {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1145 | {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1146 | #endif | ||
1147 | #ifdef CONFIG_BAND_SBAND | ||
1148 | {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, | ||
1149 | {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, | ||
1150 | #endif | ||
1151 | }; | ||
1152 | |||
1153 | static const struct dib0090_tuning dib0090_tuning_table[] = { | ||
1154 | |||
1155 | #ifdef CONFIG_BAND_CBAND | ||
1156 | {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1157 | #endif | ||
1158 | #ifdef CONFIG_BAND_VHF | ||
1159 | {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1160 | {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1161 | {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1162 | #endif | ||
1163 | #ifdef CONFIG_BAND_UHF | ||
1164 | {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1165 | {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1166 | {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1167 | {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1168 | {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1169 | {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1170 | #endif | ||
1171 | #ifdef CONFIG_BAND_LBAND | ||
1172 | {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1173 | {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1174 | {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1175 | #endif | ||
1176 | #ifdef CONFIG_BAND_SBAND | ||
1177 | {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, | ||
1178 | {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, | ||
1179 | #endif | ||
1180 | }; | ||
1181 | |||
1182 | #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ | ||
1183 | static int dib0090_tune(struct dvb_frontend *fe) | ||
1184 | { | ||
1185 | struct dib0090_state *state = fe->tuner_priv; | ||
1186 | const struct dib0090_tuning *tune = state->current_tune_table_index; | ||
1187 | const struct dib0090_pll *pll = state->current_pll_table_index; | ||
1188 | enum frontend_tune_state *tune_state = &state->tune_state; | ||
1189 | |||
1190 | u32 rf; | ||
1191 | u16 lo4 = 0xe900, lo5, lo6, Den; | ||
1192 | u32 FBDiv, Rest, FREF, VCOF_kHz = 0; | ||
1193 | u16 tmp, adc; | ||
1194 | int8_t step_sign; | ||
1195 | int ret = 10; /* 1ms is the default delay most of the time */ | ||
1196 | u8 c, i; | ||
1197 | |||
1198 | state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); | ||
1199 | rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band == | ||
1200 | BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf); | ||
1201 | /* in any case we first need to do a reset if needed */ | ||
1202 | if (state->reset & 0x1) | ||
1203 | return dib0090_dc_offset_calibration(state, tune_state); | ||
1204 | else if (state->reset & 0x2) | ||
1205 | return dib0090_wbd_calibration(state, tune_state); | ||
1206 | |||
1207 | /************************* VCO ***************************/ | ||
1208 | /* Default values for FG */ | ||
1209 | /* from these are needed : */ | ||
1210 | /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ | ||
1211 | |||
1212 | #ifdef CONFIG_SYS_ISDBT | ||
1213 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) | ||
1214 | rf += 850; | ||
1215 | #endif | ||
1216 | |||
1217 | if (state->current_rf != rf) { | ||
1218 | state->tuner_is_tuned = 0; | ||
1219 | |||
1220 | tune = dib0090_tuning_table; | ||
1221 | |||
1222 | tmp = (state->revision >> 5) & 0x7; | ||
1223 | if (tmp == 0x4 || tmp == 0x7) { | ||
1224 | /* CBAND tuner version for VHF */ | ||
1225 | if (state->current_band == BAND_FM || state->current_band == BAND_VHF) { | ||
1226 | /* Force CBAND */ | ||
1227 | state->current_band = BAND_CBAND; | ||
1228 | tune = dib0090_tuning_table_fm_vhf_on_cband; | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | pll = dib0090_pll_table; | ||
1233 | /* Look for the interval */ | ||
1234 | while (rf > tune->max_freq) | ||
1235 | tune++; | ||
1236 | while (rf > pll->max_freq) | ||
1237 | pll++; | ||
1238 | state->current_tune_table_index = tune; | ||
1239 | state->current_pll_table_index = pll; | ||
1240 | } | ||
1241 | |||
1242 | if (*tune_state == CT_TUNER_START) { | ||
1243 | |||
1244 | if (state->tuner_is_tuned == 0) | ||
1245 | state->current_rf = 0; | ||
1246 | |||
1247 | if (state->current_rf != rf) { | ||
1248 | |||
1249 | dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); | ||
1250 | |||
1251 | /* external loop filter, otherwise: | ||
1252 | * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; | ||
1253 | * lo6 = 0x0e34 */ | ||
1254 | if (pll->vco_band) | ||
1255 | lo5 = 0x049e; | ||
1256 | else if (state->config->analog_output) | ||
1257 | lo5 = 0x041d; | ||
1258 | else | ||
1259 | lo5 = 0x041c; | ||
1260 | |||
1261 | lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ | ||
1262 | |||
1263 | if (!state->config->io.pll_int_loop_filt) | ||
1264 | lo6 = 0xff28; | ||
1265 | else | ||
1266 | lo6 = (state->config->io.pll_int_loop_filt << 3); | ||
1267 | |||
1268 | VCOF_kHz = (pll->hfdiv * rf) * 2; | ||
1269 | |||
1270 | FREF = state->config->io.clock_khz; | ||
1271 | |||
1272 | FBDiv = (VCOF_kHz / pll->topresc / FREF); | ||
1273 | Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; | ||
1274 | |||
1275 | if (Rest < LPF) | ||
1276 | Rest = 0; | ||
1277 | else if (Rest < 2 * LPF) | ||
1278 | Rest = 2 * LPF; | ||
1279 | else if (Rest > (FREF - LPF)) { | ||
1280 | Rest = 0; | ||
1281 | FBDiv += 1; | ||
1282 | } else if (Rest > (FREF - 2 * LPF)) | ||
1283 | Rest = FREF - 2 * LPF; | ||
1284 | Rest = (Rest * 6528) / (FREF / 10); | ||
1285 | |||
1286 | Den = 1; | ||
1287 | |||
1288 | dprintk(" ***** ******* Rest value = %d", Rest); | ||
1289 | |||
1290 | if (Rest > 0) { | ||
1291 | if (state->config->analog_output) | ||
1292 | lo6 |= (1 << 2) | 2; | ||
1293 | else | ||
1294 | lo6 |= (1 << 2) | 1; | ||
1295 | Den = 255; | ||
1296 | } | ||
1297 | #ifdef CONFIG_BAND_SBAND | ||
1298 | if (state->current_band == BAND_SBAND) | ||
1299 | lo6 &= 0xfffb; | ||
1300 | #endif | ||
1301 | |||
1302 | dib0090_write_reg(state, 0x15, (u16) FBDiv); | ||
1303 | |||
1304 | dib0090_write_reg(state, 0x16, (Den << 8) | 1); | ||
1305 | |||
1306 | dib0090_write_reg(state, 0x17, (u16) Rest); | ||
1307 | |||
1308 | dib0090_write_reg(state, 0x19, lo5); | ||
1309 | |||
1310 | dib0090_write_reg(state, 0x1c, lo6); | ||
1311 | |||
1312 | lo6 = tune->tuner_enable; | ||
1313 | if (state->config->analog_output) | ||
1314 | lo6 = (lo6 & 0xff9f) | 0x2; | ||
1315 | |||
1316 | dib0090_write_reg(state, 0x24, lo6 | EN_LO | ||
1317 | #ifdef CONFIG_DIB0090_USE_PWM_AGC | ||
1318 | | state->config->use_pwm_agc * EN_CRYSTAL | ||
1319 | #endif | ||
1320 | ); | ||
1321 | |||
1322 | state->current_rf = rf; | ||
1323 | |||
1324 | /* prepare a complete captrim */ | ||
1325 | state->step = state->captrim = state->fcaptrim = 64; | ||
1326 | |||
1327 | } else { /* we are already tuned to this frequency - the configuration is correct */ | ||
1328 | |||
1329 | /* do a minimal captrim even if the frequency has not changed */ | ||
1330 | state->step = 4; | ||
1331 | state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; | ||
1332 | } | ||
1333 | state->adc_diff = 3000; | ||
1334 | |||
1335 | dib0090_write_reg(state, 0x10, 0x2B1); | ||
1336 | |||
1337 | dib0090_write_reg(state, 0x1e, 0x0032); | ||
1338 | |||
1339 | ret = 20; | ||
1340 | *tune_state = CT_TUNER_STEP_1; | ||
1341 | } else if (*tune_state == CT_TUNER_STEP_0) { | ||
1342 | /* nothing */ | ||
1343 | } else if (*tune_state == CT_TUNER_STEP_1) { | ||
1344 | state->step /= 2; | ||
1345 | dib0090_write_reg(state, 0x18, lo4 | state->captrim); | ||
1346 | *tune_state = CT_TUNER_STEP_2; | ||
1347 | } else if (*tune_state == CT_TUNER_STEP_2) { | ||
1348 | |||
1349 | adc = dib0090_read_reg(state, 0x1d); | ||
1350 | dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc, | ||
1351 | (u32) (adc) * (u32) 1800 / (u32) 1024); | ||
1352 | |||
1353 | if (adc >= 400) { | ||
1354 | adc -= 400; | ||
1355 | step_sign = -1; | ||
1356 | } else { | ||
1357 | adc = 400 - adc; | ||
1358 | step_sign = 1; | ||
1359 | } | ||
1360 | |||
1361 | if (adc < state->adc_diff) { | ||
1362 | dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff); | ||
1363 | state->adc_diff = adc; | ||
1364 | state->fcaptrim = state->captrim; | ||
1365 | |||
1366 | } | ||
1367 | |||
1368 | state->captrim += step_sign * state->step; | ||
1369 | if (state->step >= 1) | ||
1370 | *tune_state = CT_TUNER_STEP_1; | ||
1371 | else | ||
1372 | *tune_state = CT_TUNER_STEP_3; | ||
1373 | |||
1374 | ret = 15; | ||
1375 | } else if (*tune_state == CT_TUNER_STEP_3) { | ||
1376 | /*write the final cptrim config */ | ||
1377 | dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); | ||
1378 | |||
1379 | #ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY | ||
1380 | state->memory[state->memory_index].cap = state->fcaptrim; | ||
1381 | #endif | ||
1382 | |||
1383 | *tune_state = CT_TUNER_STEP_4; | ||
1384 | } else if (*tune_state == CT_TUNER_STEP_4) { | ||
1385 | dib0090_write_reg(state, 0x1e, 0x07ff); | ||
1386 | |||
1387 | dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim); | ||
1388 | dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code); | ||
1389 | dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band); | ||
1390 | dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf); | ||
1391 | dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz); | ||
1392 | dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); | ||
1393 | dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17), | ||
1394 | (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); | ||
1395 | |||
1396 | c = 4; | ||
1397 | i = 3; | ||
1398 | #if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) | ||
1399 | if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) { | ||
1400 | c = 2; | ||
1401 | i = 2; | ||
1402 | } | ||
1403 | #endif | ||
1404 | dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD | ||
1405 | #ifdef CONFIG_DIB0090_USE_PWM_AGC | ||
1406 | | (state->config->use_pwm_agc << 1) | ||
1407 | #endif | ||
1408 | )); | ||
1409 | dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0)); | ||
1410 | dib0090_write_reg(state, 0x0c, tune->v2i); | ||
1411 | dib0090_write_reg(state, 0x0d, tune->mix); | ||
1412 | dib0090_write_reg(state, 0x0e, tune->load); | ||
1413 | |||
1414 | *tune_state = CT_TUNER_STEP_5; | ||
1415 | } else if (*tune_state == CT_TUNER_STEP_5) { | ||
1416 | |||
1417 | /* initialize the lt gain register */ | ||
1418 | state->rf_lt_def = 0x7c00; | ||
1419 | dib0090_write_reg(state, 0x0f, state->rf_lt_def); | ||
1420 | |||
1421 | dib0090_set_bandwidth(state); | ||
1422 | state->tuner_is_tuned = 1; | ||
1423 | *tune_state = CT_TUNER_STOP; | ||
1424 | } else | ||
1425 | ret = FE_CALLBACK_TIME_NEVER; | ||
1426 | return ret; | ||
1427 | } | ||
1428 | |||
1429 | static int dib0090_release(struct dvb_frontend *fe) | ||
1430 | { | ||
1431 | kfree(fe->tuner_priv); | ||
1432 | fe->tuner_priv = NULL; | ||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) | ||
1437 | { | ||
1438 | struct dib0090_state *state = fe->tuner_priv; | ||
1439 | |||
1440 | return state->tune_state; | ||
1441 | } | ||
1442 | EXPORT_SYMBOL(dib0090_get_tune_state); | ||
1443 | |||
1444 | int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) | ||
1445 | { | ||
1446 | struct dib0090_state *state = fe->tuner_priv; | ||
1447 | |||
1448 | state->tune_state = tune_state; | ||
1449 | return 0; | ||
1450 | } | ||
1451 | EXPORT_SYMBOL(dib0090_set_tune_state); | ||
1452 | |||
1453 | static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) | ||
1454 | { | ||
1455 | struct dib0090_state *state = fe->tuner_priv; | ||
1456 | |||
1457 | *frequency = 1000 * state->current_rf; | ||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | ||
1462 | { | ||
1463 | struct dib0090_state *state = fe->tuner_priv; | ||
1464 | uint32_t ret; | ||
1465 | |||
1466 | state->tune_state = CT_TUNER_START; | ||
1467 | |||
1468 | do { | ||
1469 | ret = dib0090_tune(fe); | ||
1470 | if (ret != FE_CALLBACK_TIME_NEVER) | ||
1471 | msleep(ret / 10); | ||
1472 | else | ||
1473 | break; | ||
1474 | } while (state->tune_state != CT_TUNER_STOP); | ||
1475 | |||
1476 | return 0; | ||
1477 | } | ||
1478 | |||
1479 | static const struct dvb_tuner_ops dib0090_ops = { | ||
1480 | .info = { | ||
1481 | .name = "DiBcom DiB0090", | ||
1482 | .frequency_min = 45000000, | ||
1483 | .frequency_max = 860000000, | ||
1484 | .frequency_step = 1000, | ||
1485 | }, | ||
1486 | .release = dib0090_release, | ||
1487 | |||
1488 | .init = dib0090_wakeup, | ||
1489 | .sleep = dib0090_sleep, | ||
1490 | .set_params = dib0090_set_params, | ||
1491 | .get_frequency = dib0090_get_frequency, | ||
1492 | }; | ||
1493 | |||
1494 | struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) | ||
1495 | { | ||
1496 | struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); | ||
1497 | if (st == NULL) | ||
1498 | return NULL; | ||
1499 | |||
1500 | st->config = config; | ||
1501 | st->i2c = i2c; | ||
1502 | st->fe = fe; | ||
1503 | fe->tuner_priv = st; | ||
1504 | |||
1505 | if (dib0090_reset(fe) != 0) | ||
1506 | goto free_mem; | ||
1507 | |||
1508 | printk(KERN_INFO "DiB0090: successfully identified\n"); | ||
1509 | memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); | ||
1510 | |||
1511 | return fe; | ||
1512 | free_mem: | ||
1513 | kfree(st); | ||
1514 | fe->tuner_priv = NULL; | ||
1515 | return NULL; | ||
1516 | } | ||
1517 | EXPORT_SYMBOL(dib0090_register); | ||
1518 | |||
1519 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | ||
1520 | MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>"); | ||
1521 | MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); | ||
1522 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h new file mode 100644 index 000000000000..aa7711e88776 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. | ||
3 | * | ||
4 | * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | */ | ||
10 | #ifndef DIB0090_H | ||
11 | #define DIB0090_H | ||
12 | |||
13 | struct dvb_frontend; | ||
14 | struct i2c_adapter; | ||
15 | |||
16 | #define DEFAULT_DIB0090_I2C_ADDRESS 0x60 | ||
17 | |||
18 | struct dib0090_io_config { | ||
19 | u32 clock_khz; | ||
20 | |||
21 | u8 pll_bypass:1; | ||
22 | u8 pll_range:1; | ||
23 | u8 pll_prediv:6; | ||
24 | u8 pll_loopdiv:6; | ||
25 | |||
26 | u8 adc_clock_ratio; /* valid is 8, 7 ,6 */ | ||
27 | u16 pll_int_loop_filt; | ||
28 | }; | ||
29 | |||
30 | struct dib0090_config { | ||
31 | struct dib0090_io_config io; | ||
32 | int (*reset) (struct dvb_frontend *, int); | ||
33 | int (*sleep) (struct dvb_frontend *, int); | ||
34 | |||
35 | /* offset in kHz */ | ||
36 | int freq_offset_khz_uhf; | ||
37 | int freq_offset_khz_vhf; | ||
38 | |||
39 | int (*get_adc_power) (struct dvb_frontend *); | ||
40 | |||
41 | u8 clkouttobamse:1; /* activate or deactivate clock output */ | ||
42 | u8 analog_output; | ||
43 | |||
44 | u8 i2c_address; | ||
45 | /* add drives and other things if necessary */ | ||
46 | u16 wbd_vhf_offset; | ||
47 | u16 wbd_cband_offset; | ||
48 | u8 use_pwm_agc; | ||
49 | u8 clkoutdrive; | ||
50 | }; | ||
51 | |||
52 | #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) | ||
53 | extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); | ||
54 | extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); | ||
55 | extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); | ||
56 | extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); | ||
57 | extern int dib0090_gain_control(struct dvb_frontend *fe); | ||
58 | extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); | ||
59 | extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); | ||
60 | extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); | ||
61 | #else | ||
62 | static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) | ||
63 | { | ||
64 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) | ||
69 | { | ||
70 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
71 | } | ||
72 | |||
73 | static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) | ||
74 | { | ||
75 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
76 | } | ||
77 | |||
78 | static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) | ||
79 | { | ||
80 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static inline int dib0090_gain_control(struct dvb_frontend *fe) | ||
85 | { | ||
86 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
87 | return -ENODEV; | ||
88 | } | ||
89 | |||
90 | static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) | ||
91 | { | ||
92 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
93 | return CT_DONE; | ||
94 | } | ||
95 | |||
96 | static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) | ||
97 | { | ||
98 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
99 | return -ENODEV; | ||
100 | } | ||
101 | |||
102 | static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) | ||
103 | { | ||
104 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | #endif | ||
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 898400d331a3..6f6fa29d9ea4 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c | |||
@@ -28,18 +28,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | |||
28 | 28 | ||
29 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) | 29 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) |
30 | 30 | ||
31 | enum frontend_tune_state { | ||
32 | CT_AGC_START = 20, | ||
33 | CT_AGC_STEP_0, | ||
34 | CT_AGC_STEP_1, | ||
35 | CT_AGC_STEP_2, | ||
36 | CT_AGC_STEP_3, | ||
37 | CT_AGC_STEP_4, | ||
38 | CT_AGC_STOP, | ||
39 | |||
40 | CT_DEMOD_START = 30, | ||
41 | }; | ||
42 | |||
43 | #define FE_STATUS_TUNE_FAILED 0 | 31 | #define FE_STATUS_TUNE_FAILED 0 |
44 | 32 | ||
45 | struct i2c_device { | 33 | struct i2c_device { |
@@ -133,104 +121,104 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) | |||
133 | return dib8000_i2c_write16(&state->i2c, reg, val); | 121 | return dib8000_i2c_write16(&state->i2c, reg, val); |
134 | } | 122 | } |
135 | 123 | ||
136 | const int16_t coeff_2k_sb_1seg_dqpsk[8] = { | 124 | static const int16_t coeff_2k_sb_1seg_dqpsk[8] = { |
137 | (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, | 125 | (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, |
138 | (920 << 5) | 0x09 | 126 | (920 << 5) | 0x09 |
139 | }; | 127 | }; |
140 | 128 | ||
141 | const int16_t coeff_2k_sb_1seg[8] = { | 129 | static const int16_t coeff_2k_sb_1seg[8] = { |
142 | (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f | 130 | (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f |
143 | }; | 131 | }; |
144 | 132 | ||
145 | const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { | 133 | static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { |
146 | (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, | 134 | (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, |
147 | (-931 << 5) | 0x0f | 135 | (-931 << 5) | 0x0f |
148 | }; | 136 | }; |
149 | 137 | ||
150 | const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { | 138 | static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { |
151 | (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, | 139 | (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, |
152 | (982 << 5) | 0x0c | 140 | (982 << 5) | 0x0c |
153 | }; | 141 | }; |
154 | 142 | ||
155 | const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { | 143 | static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { |
156 | (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, | 144 | (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, |
157 | (-720 << 5) | 0x0d | 145 | (-720 << 5) | 0x0d |
158 | }; | 146 | }; |
159 | 147 | ||
160 | const int16_t coeff_2k_sb_3seg[8] = { | 148 | static const int16_t coeff_2k_sb_3seg[8] = { |
161 | (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, | 149 | (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, |
162 | (-610 << 5) | 0x0a | 150 | (-610 << 5) | 0x0a |
163 | }; | 151 | }; |
164 | 152 | ||
165 | const int16_t coeff_4k_sb_1seg_dqpsk[8] = { | 153 | static const int16_t coeff_4k_sb_1seg_dqpsk[8] = { |
166 | (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, | 154 | (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, |
167 | (-922 << 5) | 0x0d | 155 | (-922 << 5) | 0x0d |
168 | }; | 156 | }; |
169 | 157 | ||
170 | const int16_t coeff_4k_sb_1seg[8] = { | 158 | static const int16_t coeff_4k_sb_1seg[8] = { |
171 | (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, | 159 | (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, |
172 | (-655 << 5) | 0x0a | 160 | (-655 << 5) | 0x0a |
173 | }; | 161 | }; |
174 | 162 | ||
175 | const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { | 163 | static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { |
176 | (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, | 164 | (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, |
177 | (-958 << 5) | 0x13 | 165 | (-958 << 5) | 0x13 |
178 | }; | 166 | }; |
179 | 167 | ||
180 | const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { | 168 | static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { |
181 | (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, | 169 | (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, |
182 | (-568 << 5) | 0x0f | 170 | (-568 << 5) | 0x0f |
183 | }; | 171 | }; |
184 | 172 | ||
185 | const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { | 173 | static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { |
186 | (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, | 174 | (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, |
187 | (-848 << 5) | 0x13 | 175 | (-848 << 5) | 0x13 |
188 | }; | 176 | }; |
189 | 177 | ||
190 | const int16_t coeff_4k_sb_3seg[8] = { | 178 | static const int16_t coeff_4k_sb_3seg[8] = { |
191 | (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, | 179 | (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, |
192 | (-869 << 5) | 0x13 | 180 | (-869 << 5) | 0x13 |
193 | }; | 181 | }; |
194 | 182 | ||
195 | const int16_t coeff_8k_sb_1seg_dqpsk[8] = { | 183 | static const int16_t coeff_8k_sb_1seg_dqpsk[8] = { |
196 | (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, | 184 | (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, |
197 | (-598 << 5) | 0x10 | 185 | (-598 << 5) | 0x10 |
198 | }; | 186 | }; |
199 | 187 | ||
200 | const int16_t coeff_8k_sb_1seg[8] = { | 188 | static const int16_t coeff_8k_sb_1seg[8] = { |
201 | (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, | 189 | (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, |
202 | (585 << 5) | 0x0f | 190 | (585 << 5) | 0x0f |
203 | }; | 191 | }; |
204 | 192 | ||
205 | const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { | 193 | static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { |
206 | (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, | 194 | (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, |
207 | (0 << 5) | 0x14 | 195 | (0 << 5) | 0x14 |
208 | }; | 196 | }; |
209 | 197 | ||
210 | const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { | 198 | static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { |
211 | (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, | 199 | (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, |
212 | (-877 << 5) | 0x15 | 200 | (-877 << 5) | 0x15 |
213 | }; | 201 | }; |
214 | 202 | ||
215 | const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { | 203 | static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { |
216 | (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, | 204 | (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, |
217 | (-921 << 5) | 0x14 | 205 | (-921 << 5) | 0x14 |
218 | }; | 206 | }; |
219 | 207 | ||
220 | const int16_t coeff_8k_sb_3seg[8] = { | 208 | static const int16_t coeff_8k_sb_3seg[8] = { |
221 | (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, | 209 | (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, |
222 | (690 << 5) | 0x14 | 210 | (690 << 5) | 0x14 |
223 | }; | 211 | }; |
224 | 212 | ||
225 | const int16_t ana_fe_coeff_3seg[24] = { | 213 | static const int16_t ana_fe_coeff_3seg[24] = { |
226 | 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 | 214 | 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 |
227 | }; | 215 | }; |
228 | 216 | ||
229 | const int16_t ana_fe_coeff_1seg[24] = { | 217 | static const int16_t ana_fe_coeff_1seg[24] = { |
230 | 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 | 218 | 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 |
231 | }; | 219 | }; |
232 | 220 | ||
233 | const int16_t ana_fe_coeff_13seg[24] = { | 221 | static const int16_t ana_fe_coeff_13seg[24] = { |
234 | 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 | 222 | 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 |
235 | }; | 223 | }; |
236 | 224 | ||
@@ -852,6 +840,14 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) | |||
852 | return 0; | 840 | return 0; |
853 | } | 841 | } |
854 | 842 | ||
843 | void dib8000_pwm_agc_reset(struct dvb_frontend *fe) | ||
844 | { | ||
845 | struct dib8000_state *state = fe->demodulator_priv; | ||
846 | dib8000_set_adc_state(state, DIBX000_ADC_ON); | ||
847 | dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); | ||
848 | } | ||
849 | EXPORT_SYMBOL(dib8000_pwm_agc_reset); | ||
850 | |||
855 | static int dib8000_agc_soft_split(struct dib8000_state *state) | 851 | static int dib8000_agc_soft_split(struct dib8000_state *state) |
856 | { | 852 | { |
857 | u16 agc, split_offset; | 853 | u16 agc, split_offset; |
@@ -939,6 +935,32 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) | |||
939 | 935 | ||
940 | } | 936 | } |
941 | 937 | ||
938 | static const int32_t lut_1000ln_mant[] = | ||
939 | { | ||
940 | 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 | ||
941 | }; | ||
942 | |||
943 | int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode) | ||
944 | { | ||
945 | struct dib8000_state *state = fe->demodulator_priv; | ||
946 | uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0; | ||
947 | int32_t val; | ||
948 | |||
949 | val = dib8000_read32(state, 384); | ||
950 | /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ | ||
951 | if (mode) { | ||
952 | tmp_val = val; | ||
953 | while (tmp_val >>= 1) | ||
954 | exp++; | ||
955 | mant = (val * 1000 / (1<<exp)); | ||
956 | ix = (uint8_t)((mant-1000)/100); /* index of the LUT */ | ||
957 | val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */ | ||
958 | val = (val*256)/1000; | ||
959 | } | ||
960 | return val; | ||
961 | } | ||
962 | EXPORT_SYMBOL(dib8000_get_adc_power); | ||
963 | |||
942 | static void dib8000_update_timf(struct dib8000_state *state) | 964 | static void dib8000_update_timf(struct dib8000_state *state) |
943 | { | 965 | { |
944 | u32 timf = state->timf = dib8000_read32(state, 435); | 966 | u32 timf = state->timf = dib8000_read32(state, 435); |
@@ -1401,10 +1423,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear | |||
1401 | } | 1423 | } |
1402 | break; | 1424 | break; |
1403 | } | 1425 | } |
1404 | } | ||
1405 | if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) | ||
1406 | for (i = 0; i < 8; i++) | 1426 | for (i = 0; i < 8; i++) |
1407 | dib8000_write_word(state, 343 + i, ncoeff[i]); | 1427 | dib8000_write_word(state, 343 + i, ncoeff[i]); |
1428 | } | ||
1408 | 1429 | ||
1409 | // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 | 1430 | // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 |
1410 | dib8000_write_word(state, 351, | 1431 | dib8000_write_word(state, 351, |
@@ -1854,6 +1875,24 @@ static int dib8000_sleep(struct dvb_frontend *fe) | |||
1854 | } | 1875 | } |
1855 | } | 1876 | } |
1856 | 1877 | ||
1878 | enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) | ||
1879 | { | ||
1880 | struct dib8000_state *state = fe->demodulator_priv; | ||
1881 | return state->tune_state; | ||
1882 | } | ||
1883 | EXPORT_SYMBOL(dib8000_get_tune_state); | ||
1884 | |||
1885 | int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) | ||
1886 | { | ||
1887 | struct dib8000_state *state = fe->demodulator_priv; | ||
1888 | state->tune_state = tune_state; | ||
1889 | return 0; | ||
1890 | } | ||
1891 | EXPORT_SYMBOL(dib8000_set_tune_state); | ||
1892 | |||
1893 | |||
1894 | |||
1895 | |||
1857 | static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) | 1896 | static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) |
1858 | { | 1897 | { |
1859 | struct dib8000_state *state = fe->demodulator_priv; | 1898 | struct dib8000_state *state = fe->demodulator_priv; |
@@ -2043,29 +2082,31 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) | |||
2043 | 2082 | ||
2044 | *stat = 0; | 2083 | *stat = 0; |
2045 | 2084 | ||
2046 | if ((lock >> 14) & 1) // AGC | 2085 | if ((lock >> 13) & 1) |
2047 | *stat |= FE_HAS_SIGNAL; | 2086 | *stat |= FE_HAS_SIGNAL; |
2048 | 2087 | ||
2049 | if ((lock >> 8) & 1) // Equal | 2088 | if ((lock >> 8) & 1) /* Equal */ |
2050 | *stat |= FE_HAS_CARRIER; | 2089 | *stat |= FE_HAS_CARRIER; |
2051 | 2090 | ||
2052 | if ((lock >> 3) & 1) // TMCC_SYNC | 2091 | if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */ |
2053 | *stat |= FE_HAS_SYNC; | 2092 | *stat |= FE_HAS_SYNC; |
2054 | 2093 | ||
2055 | if ((lock >> 5) & 7) // FEC MPEG | 2094 | if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */ |
2056 | *stat |= FE_HAS_LOCK; | 2095 | *stat |= FE_HAS_LOCK; |
2057 | 2096 | ||
2058 | lock = dib8000_read_word(state, 554); // Viterbi Layer A | 2097 | if ((lock >> 12) & 1) { |
2059 | if (lock & 0x01) | 2098 | lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ |
2060 | *stat |= FE_HAS_VITERBI; | 2099 | if (lock & 0x01) |
2100 | *stat |= FE_HAS_VITERBI; | ||
2061 | 2101 | ||
2062 | lock = dib8000_read_word(state, 555); // Viterbi Layer B | 2102 | lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ |
2063 | if (lock & 0x01) | 2103 | if (lock & 0x01) |
2064 | *stat |= FE_HAS_VITERBI; | 2104 | *stat |= FE_HAS_VITERBI; |
2065 | 2105 | ||
2066 | lock = dib8000_read_word(state, 556); // Viterbi Layer C | 2106 | lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ |
2067 | if (lock & 0x01) | 2107 | if (lock & 0x01) |
2068 | *stat |= FE_HAS_VITERBI; | 2108 | *stat |= FE_HAS_VITERBI; |
2109 | } | ||
2069 | 2110 | ||
2070 | return 0; | 2111 | return 0; |
2071 | } | 2112 | } |
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 8c89482b738a..d99619ae983c 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h | |||
@@ -46,6 +46,10 @@ extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | |||
46 | extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); | 46 | extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); |
47 | extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); | 47 | extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); |
48 | extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); | 48 | extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); |
49 | extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); | ||
50 | extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); | ||
51 | extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); | ||
52 | extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); | ||
49 | #else | 53 | #else |
50 | static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) | 54 | static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) |
51 | { | 55 | { |
@@ -59,35 +63,53 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe | |||
59 | return NULL; | 63 | return NULL; |
60 | } | 64 | } |
61 | 65 | ||
62 | int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) | 66 | static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) |
63 | { | 67 | { |
64 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 68 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
65 | return -ENODEV; | 69 | return -ENODEV; |
66 | } | 70 | } |
67 | 71 | ||
68 | int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) | 72 | static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) |
69 | { | 73 | { |
70 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 74 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
71 | return -ENODEV; | 75 | return -ENODEV; |
72 | } | 76 | } |
73 | 77 | ||
74 | int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) | 78 | static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) |
75 | { | 79 | { |
76 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 80 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
77 | return -ENODEV; | 81 | return -ENODEV; |
78 | } | 82 | } |
79 | 83 | ||
80 | int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) | 84 | static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) |
81 | { | 85 | { |
82 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 86 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
83 | return -ENODEV; | 87 | return -ENODEV; |
84 | } | 88 | } |
85 | 89 | ||
86 | int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) | 90 | static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) |
87 | { | 91 | { |
88 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 92 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
89 | return -ENODEV; | 93 | return -ENODEV; |
90 | } | 94 | } |
95 | static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) | ||
96 | { | ||
97 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
98 | return -ENODEV; | ||
99 | } | ||
100 | static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) | ||
101 | { | ||
102 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
103 | return CT_SHUTDOWN, | ||
104 | } | ||
105 | static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) | ||
106 | { | ||
107 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
108 | } | ||
109 | static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) | ||
110 | { | ||
111 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
112 | } | ||
91 | #endif | 113 | #endif |
92 | 114 | ||
93 | #endif | 115 | #endif |
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 4efca30d2127..e6f3d73db9d3 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c | |||
@@ -6,7 +6,7 @@ static int debug; | |||
6 | module_param(debug, int, 0644); | 6 | module_param(debug, int, 0644); |
7 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | 7 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); |
8 | 8 | ||
9 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0) | 9 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) |
10 | 10 | ||
11 | static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) | 11 | static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) |
12 | { | 12 | { |
@@ -25,7 +25,7 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, | |||
25 | enum dibx000_i2c_interface intf) | 25 | enum dibx000_i2c_interface intf) |
26 | { | 26 | { |
27 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { | 27 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { |
28 | dprintk("selecting interface: %d\n", intf); | 28 | dprintk("selecting interface: %d", intf); |
29 | mst->selected_interface = intf; | 29 | mst->selected_interface = intf; |
30 | return dibx000_write_word(mst, mst->base_reg + 4, intf); | 30 | return dibx000_write_word(mst, mst->base_reg + 4, intf); |
31 | } | 31 | } |
@@ -171,9 +171,18 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) | |||
171 | { | 171 | { |
172 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); | 172 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); |
173 | } | 173 | } |
174 | |||
175 | EXPORT_SYMBOL(dibx000_exit_i2c_master); | 174 | EXPORT_SYMBOL(dibx000_exit_i2c_master); |
176 | 175 | ||
176 | |||
177 | u32 systime() | ||
178 | { | ||
179 | struct timespec t; | ||
180 | |||
181 | t = current_kernel_time(); | ||
182 | return (t.tv_sec * 10000) + (t.tv_nsec / 100000); | ||
183 | } | ||
184 | EXPORT_SYMBOL(systime); | ||
185 | |||
177 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | 186 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); |
178 | MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); | 187 | MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); |
179 | MODULE_LICENSE("GPL"); | 188 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5be10eca07c0..4f5d141a308d 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h | |||
@@ -36,13 +36,17 @@ extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master | |||
36 | extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); | 36 | extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); |
37 | extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); | 37 | extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); |
38 | 38 | ||
39 | extern u32 systime(void); | ||
40 | |||
39 | #define BAND_LBAND 0x01 | 41 | #define BAND_LBAND 0x01 |
40 | #define BAND_UHF 0x02 | 42 | #define BAND_UHF 0x02 |
41 | #define BAND_VHF 0x04 | 43 | #define BAND_VHF 0x04 |
42 | #define BAND_SBAND 0x08 | 44 | #define BAND_SBAND 0x08 |
43 | #define BAND_FM 0x10 | 45 | #define BAND_FM 0x10 |
46 | #define BAND_CBAND 0x20 | ||
44 | 47 | ||
45 | #define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \ | 48 | #define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ |
49 | (freq_kHz) <= 115000 ? BAND_FM : \ | ||
46 | (freq_kHz) <= 250000 ? BAND_VHF : \ | 50 | (freq_kHz) <= 250000 ? BAND_VHF : \ |
47 | (freq_kHz) <= 863000 ? BAND_UHF : \ | 51 | (freq_kHz) <= 863000 ? BAND_UHF : \ |
48 | (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) | 52 | (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) |
@@ -149,4 +153,67 @@ enum dibx000_adc_states { | |||
149 | #define OUTMODE_MPEG2_FIFO 5 | 153 | #define OUTMODE_MPEG2_FIFO 5 |
150 | #define OUTMODE_ANALOG_ADC 6 | 154 | #define OUTMODE_ANALOG_ADC 6 |
151 | 155 | ||
156 | enum frontend_tune_state { | ||
157 | CT_TUNER_START = 10, | ||
158 | CT_TUNER_STEP_0, | ||
159 | CT_TUNER_STEP_1, | ||
160 | CT_TUNER_STEP_2, | ||
161 | CT_TUNER_STEP_3, | ||
162 | CT_TUNER_STEP_4, | ||
163 | CT_TUNER_STEP_5, | ||
164 | CT_TUNER_STEP_6, | ||
165 | CT_TUNER_STEP_7, | ||
166 | CT_TUNER_STOP, | ||
167 | |||
168 | CT_AGC_START = 20, | ||
169 | CT_AGC_STEP_0, | ||
170 | CT_AGC_STEP_1, | ||
171 | CT_AGC_STEP_2, | ||
172 | CT_AGC_STEP_3, | ||
173 | CT_AGC_STEP_4, | ||
174 | CT_AGC_STOP, | ||
175 | |||
176 | CT_DEMOD_START = 30, | ||
177 | CT_DEMOD_STEP_1, | ||
178 | CT_DEMOD_STEP_2, | ||
179 | CT_DEMOD_STEP_3, | ||
180 | CT_DEMOD_STEP_4, | ||
181 | CT_DEMOD_STEP_5, | ||
182 | CT_DEMOD_STEP_6, | ||
183 | CT_DEMOD_STEP_7, | ||
184 | CT_DEMOD_STEP_8, | ||
185 | CT_DEMOD_STEP_9, | ||
186 | CT_DEMOD_STEP_10, | ||
187 | CT_DEMOD_SEARCH_NEXT = 41, | ||
188 | CT_DEMOD_STEP_LOCKED, | ||
189 | CT_DEMOD_STOP, | ||
190 | |||
191 | CT_DONE = 100, | ||
192 | CT_SHUTDOWN, | ||
193 | |||
194 | }; | ||
195 | |||
196 | struct dvb_frontend_parametersContext { | ||
197 | #define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 | ||
198 | #define CHANNEL_STATUS_PARAMETERS_SET 0x02 | ||
199 | u8 status; | ||
200 | u32 tune_time_estimation[2]; | ||
201 | s32 tps_available; | ||
202 | u16 tps[9]; | ||
203 | }; | ||
204 | |||
205 | #define FE_STATUS_TUNE_FAILED 0 | ||
206 | #define FE_STATUS_TUNE_TIMED_OUT -1 | ||
207 | #define FE_STATUS_TUNE_TIME_TOO_SHORT -2 | ||
208 | #define FE_STATUS_TUNE_PENDING -3 | ||
209 | #define FE_STATUS_STD_SUCCESS -4 | ||
210 | #define FE_STATUS_FFT_SUCCESS -5 | ||
211 | #define FE_STATUS_DEMOD_SUCCESS -6 | ||
212 | #define FE_STATUS_LOCKED -7 | ||
213 | #define FE_STATUS_DATA_LOCKED -8 | ||
214 | |||
215 | #define FE_CALLBACK_TIME_NEVER 0xffffffff | ||
216 | |||
217 | #define ABS(x) ((x < 0) ? (-x) : (x)) | ||
218 | |||
152 | #endif | 219 | #endif |
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index eabcadc425d5..dee53960e7e8 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c | |||
@@ -199,7 +199,7 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) | |||
199 | 199 | ||
200 | val = freq; | 200 | val = freq; |
201 | if (freq != 0) { | 201 | if (freq != 0) { |
202 | val *= (u64)1 << 32; | 202 | val <<= 32; |
203 | if (if_clk != 0) | 203 | if (if_clk != 0) |
204 | do_div(val, if_clk); | 204 | do_div(val, if_clk); |
205 | v32 = val & 0xFFFFFFFF; | 205 | v32 = val & 0xFFFFFFFF; |
@@ -246,7 +246,7 @@ static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) | |||
246 | 246 | ||
247 | val = v32; | 247 | val = v32; |
248 | val *= priv->config->if_clk_freq; | 248 | val *= priv->config->if_clk_freq; |
249 | val /= (u64)1 << 32; | 249 | val >>= 32; |
250 | dprintk("AFC = %u kHz\n", (u32)val); | 250 | dprintk("AFC = %u kHz\n", (u32)val); |
251 | return 0; | 251 | return 0; |
252 | } | 252 | } |
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 71f607fe8fc7..b181bf023ada 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lnbp21.c - driver for lnb supply and control ic lnbp21 | 2 | * lnbp21.c - driver for lnb supply and control ic lnbp21 |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Oliver Endriss | 4 | * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de> |
5 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | 5 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -91,6 +91,31 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) | |||
91 | return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; | 91 | return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; |
92 | } | 92 | } |
93 | 93 | ||
94 | static int lnbp21_set_tone(struct dvb_frontend *fe, | ||
95 | fe_sec_tone_mode_t tone) | ||
96 | { | ||
97 | struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; | ||
98 | struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, | ||
99 | .buf = &lnbp21->config, | ||
100 | .len = sizeof(lnbp21->config) }; | ||
101 | |||
102 | switch (tone) { | ||
103 | case SEC_TONE_OFF: | ||
104 | lnbp21->config &= ~LNBP21_TEN; | ||
105 | break; | ||
106 | case SEC_TONE_ON: | ||
107 | lnbp21->config |= LNBP21_TEN; | ||
108 | break; | ||
109 | default: | ||
110 | return -EINVAL; | ||
111 | }; | ||
112 | |||
113 | lnbp21->config |= lnbp21->override_or; | ||
114 | lnbp21->config &= lnbp21->override_and; | ||
115 | |||
116 | return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; | ||
117 | } | ||
118 | |||
94 | static void lnbp21_release(struct dvb_frontend *fe) | 119 | static void lnbp21_release(struct dvb_frontend *fe) |
95 | { | 120 | { |
96 | /* LNBP power off */ | 121 | /* LNBP power off */ |
@@ -133,6 +158,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, | |||
133 | /* override frontend ops */ | 158 | /* override frontend ops */ |
134 | fe->ops.set_voltage = lnbp21_set_voltage; | 159 | fe->ops.set_voltage = lnbp21_set_voltage; |
135 | fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; | 160 | fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; |
161 | fe->ops.set_tone = lnbp21_set_tone; | ||
136 | printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); | 162 | printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); |
137 | 163 | ||
138 | return fe; | 164 | return fe; |
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index df49ea0983bc..8762c86044a5 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c | |||
@@ -1451,6 +1451,8 @@ static int stv0900_status(struct stv0900_internal *intp, | |||
1451 | { | 1451 | { |
1452 | enum fe_stv0900_search_state demod_state; | 1452 | enum fe_stv0900_search_state demod_state; |
1453 | int locked = FALSE; | 1453 | int locked = FALSE; |
1454 | u8 tsbitrate0_val, tsbitrate1_val; | ||
1455 | s32 bitrate; | ||
1454 | 1456 | ||
1455 | demod_state = stv0900_get_bits(intp, HEADER_MODE); | 1457 | demod_state = stv0900_get_bits(intp, HEADER_MODE); |
1456 | switch (demod_state) { | 1458 | switch (demod_state) { |
@@ -1473,6 +1475,17 @@ static int stv0900_status(struct stv0900_internal *intp, | |||
1473 | 1475 | ||
1474 | dprintk("%s: locked = %d\n", __func__, locked); | 1476 | dprintk("%s: locked = %d\n", __func__, locked); |
1475 | 1477 | ||
1478 | if (stvdebug) { | ||
1479 | /* Print TS bitrate */ | ||
1480 | tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0); | ||
1481 | tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1); | ||
1482 | /* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */ | ||
1483 | bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) | ||
1484 | * (tsbitrate1_val << 8 | tsbitrate0_val); | ||
1485 | bitrate /= 16384; | ||
1486 | dprintk("TS bitrate = %d Mbit/sec \n", bitrate); | ||
1487 | }; | ||
1488 | |||
1476 | return locked; | 1489 | return locked; |
1477 | } | 1490 | } |
1478 | 1491 | ||
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 48edd542242e..1573466a5c74 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c | |||
@@ -3597,7 +3597,8 @@ static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma | |||
3597 | 3597 | ||
3598 | reg = STV090x_READ_DEMOD(state, DISTXCTL); | 3598 | reg = STV090x_READ_DEMOD(state, DISTXCTL); |
3599 | 3599 | ||
3600 | STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2); | 3600 | STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, |
3601 | (state->config->diseqc_envelope_mode) ? 4 : 2); | ||
3601 | STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); | 3602 | STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); |
3602 | if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) | 3603 | if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) |
3603 | goto err; | 3604 | goto err; |
@@ -3649,10 +3650,10 @@ static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t | |||
3649 | reg = STV090x_READ_DEMOD(state, DISTXCTL); | 3650 | reg = STV090x_READ_DEMOD(state, DISTXCTL); |
3650 | 3651 | ||
3651 | if (burst == SEC_MINI_A) { | 3652 | if (burst == SEC_MINI_A) { |
3652 | mode = 3; | 3653 | mode = (state->config->diseqc_envelope_mode) ? 5 : 3; |
3653 | value = 0x00; | 3654 | value = 0x00; |
3654 | } else { | 3655 | } else { |
3655 | mode = 2; | 3656 | mode = (state->config->diseqc_envelope_mode) ? 4 : 2; |
3656 | value = 0xFF; | 3657 | value = 0xFF; |
3657 | } | 3658 | } |
3658 | 3659 | ||
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index e968c98bb70f..b133807663ea 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h | |||
@@ -75,6 +75,8 @@ struct stv090x_config { | |||
75 | 75 | ||
76 | enum stv090x_i2crpt repeater_level; | 76 | enum stv090x_i2crpt repeater_level; |
77 | 77 | ||
78 | bool diseqc_envelope_mode; | ||
79 | |||
78 | int (*tuner_init) (struct dvb_frontend *fe); | 80 | int (*tuner_init) (struct dvb_frontend *fe); |
79 | int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); | 81 | int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); |
80 | int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); | 82 | int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); |
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 266033ae2784..68bf9fbd8fed 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c | |||
@@ -662,7 +662,7 @@ adapter_error: | |||
662 | return rc; | 662 | return rc; |
663 | } | 663 | } |
664 | 664 | ||
665 | int smsdvb_module_init(void) | 665 | static int __init smsdvb_module_init(void) |
666 | { | 666 | { |
667 | int rc; | 667 | int rc; |
668 | 668 | ||
@@ -676,7 +676,7 @@ int smsdvb_module_init(void) | |||
676 | return rc; | 676 | return rc; |
677 | } | 677 | } |
678 | 678 | ||
679 | void smsdvb_module_exit(void) | 679 | static void __exit smsdvb_module_exit(void) |
680 | { | 680 | { |
681 | smscore_unregister_hotplug(smsdvb_hotplug); | 681 | smscore_unregister_hotplug(smsdvb_hotplug); |
682 | 682 | ||
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c index 24206cbda264..195244a3e69b 100644 --- a/drivers/media/dvb/siano/smssdio.c +++ b/drivers/media/dvb/siano/smssdio.c | |||
@@ -48,7 +48,7 @@ | |||
48 | #define SMSSDIO_INT 0x04 | 48 | #define SMSSDIO_INT 0x04 |
49 | #define SMSSDIO_BLOCK_SIZE 128 | 49 | #define SMSSDIO_BLOCK_SIZE 128 |
50 | 50 | ||
51 | static const struct sdio_device_id smssdio_ids[] = { | 51 | static const struct sdio_device_id smssdio_ids[] __devinitconst = { |
52 | {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), | 52 | {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), |
53 | .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, | 53 | .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, |
54 | {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), | 54 | {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), |
@@ -222,7 +222,7 @@ static void smssdio_interrupt(struct sdio_func *func) | |||
222 | smscore_onresponse(smsdev->coredev, cb); | 222 | smscore_onresponse(smsdev->coredev, cb); |
223 | } | 223 | } |
224 | 224 | ||
225 | static int smssdio_probe(struct sdio_func *func, | 225 | static int __devinit smssdio_probe(struct sdio_func *func, |
226 | const struct sdio_device_id *id) | 226 | const struct sdio_device_id *id) |
227 | { | 227 | { |
228 | int ret; | 228 | int ret; |
@@ -338,7 +338,7 @@ static struct sdio_driver smssdio_driver = { | |||
338 | /* Module functions */ | 338 | /* Module functions */ |
339 | /*******************************************************************/ | 339 | /*******************************************************************/ |
340 | 340 | ||
341 | int smssdio_module_init(void) | 341 | static int __init smssdio_module_init(void) |
342 | { | 342 | { |
343 | int ret = 0; | 343 | int ret = 0; |
344 | 344 | ||
@@ -350,7 +350,7 @@ int smssdio_module_init(void) | |||
350 | return ret; | 350 | return ret; |
351 | } | 351 | } |
352 | 352 | ||
353 | void smssdio_module_exit(void) | 353 | static void __exit smssdio_module_exit(void) |
354 | { | 354 | { |
355 | sdio_unregister_driver(&smssdio_driver); | 355 | sdio_unregister_driver(&smssdio_driver); |
356 | } | 356 | } |
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 8f88a586b0dd..5eac27287d9c 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c | |||
@@ -390,7 +390,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) | |||
390 | return rc; | 390 | return rc; |
391 | } | 391 | } |
392 | 392 | ||
393 | static int smsusb_probe(struct usb_interface *intf, | 393 | static int __devinit smsusb_probe(struct usb_interface *intf, |
394 | const struct usb_device_id *id) | 394 | const struct usb_device_id *id) |
395 | { | 395 | { |
396 | struct usb_device *udev = interface_to_usbdev(intf); | 396 | struct usb_device *udev = interface_to_usbdev(intf); |
@@ -484,7 +484,7 @@ static int smsusb_resume(struct usb_interface *intf) | |||
484 | return 0; | 484 | return 0; |
485 | } | 485 | } |
486 | 486 | ||
487 | struct usb_device_id smsusb_id_table[] = { | 487 | static const struct usb_device_id smsusb_id_table[] __devinitconst = { |
488 | { USB_DEVICE(0x187f, 0x0010), | 488 | { USB_DEVICE(0x187f, 0x0010), |
489 | .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, | 489 | .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, |
490 | { USB_DEVICE(0x187f, 0x0100), | 490 | { USB_DEVICE(0x187f, 0x0100), |
@@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = { | |||
533 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | 533 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, |
534 | { USB_DEVICE(0x2040, 0xb910), | 534 | { USB_DEVICE(0x2040, 0xb910), |
535 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | 535 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, |
536 | { USB_DEVICE(0x2040, 0xb980), | ||
537 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | ||
538 | { USB_DEVICE(0x2040, 0xb990), | ||
539 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | ||
536 | { USB_DEVICE(0x2040, 0xc000), | 540 | { USB_DEVICE(0x2040, 0xc000), |
537 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | 541 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, |
542 | { USB_DEVICE(0x2040, 0xc010), | ||
543 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | ||
544 | { USB_DEVICE(0x2040, 0xc080), | ||
545 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | ||
546 | { USB_DEVICE(0x2040, 0xc090), | ||
547 | .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, | ||
538 | { } /* Terminating entry */ | 548 | { } /* Terminating entry */ |
539 | }; | 549 | }; |
540 | 550 | ||
@@ -550,7 +560,7 @@ static struct usb_driver smsusb_driver = { | |||
550 | .resume = smsusb_resume, | 560 | .resume = smsusb_resume, |
551 | }; | 561 | }; |
552 | 562 | ||
553 | int smsusb_module_init(void) | 563 | static int __init smsusb_module_init(void) |
554 | { | 564 | { |
555 | int rc = usb_register(&smsusb_driver); | 565 | int rc = usb_register(&smsusb_driver); |
556 | if (rc) | 566 | if (rc) |
@@ -561,7 +571,7 @@ int smsusb_module_init(void) | |||
561 | return rc; | 571 | return rc; |
562 | } | 572 | } |
563 | 573 | ||
564 | void smsusb_module_exit(void) | 574 | static void __exit smsusb_module_exit(void) |
565 | { | 575 | { |
566 | /* Regular USB Cleanup */ | 576 | /* Regular USB Cleanup */ |
567 | usb_deregister(&smsusb_driver); | 577 | usb_deregister(&smsusb_driver); |
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 7d193ebc0aea..9782e0593733 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c | |||
@@ -190,12 +190,13 @@ static int msp430_ir_init(struct budget_ci *budget_ci) | |||
190 | struct saa7146_dev *saa = budget_ci->budget.dev; | 190 | struct saa7146_dev *saa = budget_ci->budget.dev; |
191 | struct input_dev *input_dev = budget_ci->ir.dev; | 191 | struct input_dev *input_dev = budget_ci->ir.dev; |
192 | int error; | 192 | int error; |
193 | struct ir_scancode_table *ir_codes; | ||
194 | |||
193 | 195 | ||
194 | budget_ci->ir.dev = input_dev = input_allocate_device(); | 196 | budget_ci->ir.dev = input_dev = input_allocate_device(); |
195 | if (!input_dev) { | 197 | if (!input_dev) { |
196 | printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); | 198 | printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); |
197 | error = -ENOMEM; | 199 | return -ENOMEM; |
198 | goto out1; | ||
199 | } | 200 | } |
200 | 201 | ||
201 | snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), | 202 | snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), |
@@ -217,6 +218,11 @@ static int msp430_ir_init(struct budget_ci *budget_ci) | |||
217 | } | 218 | } |
218 | input_dev->dev.parent = &saa->pci->dev; | 219 | input_dev->dev.parent = &saa->pci->dev; |
219 | 220 | ||
221 | if (rc5_device < 0) | ||
222 | budget_ci->ir.rc5_device = IR_DEVICE_ANY; | ||
223 | else | ||
224 | budget_ci->ir.rc5_device = rc5_device; | ||
225 | |||
220 | /* Select keymap and address */ | 226 | /* Select keymap and address */ |
221 | switch (budget_ci->budget.dev->pci->subsystem_device) { | 227 | switch (budget_ci->budget.dev->pci->subsystem_device) { |
222 | case 0x100c: | 228 | case 0x100c: |
@@ -224,53 +230,34 @@ static int msp430_ir_init(struct budget_ci *budget_ci) | |||
224 | case 0x1011: | 230 | case 0x1011: |
225 | case 0x1012: | 231 | case 0x1012: |
226 | /* The hauppauge keymap is a superset of these remotes */ | 232 | /* The hauppauge keymap is a superset of these remotes */ |
227 | error = ir_input_init(input_dev, &budget_ci->ir.state, | 233 | ir_codes = &ir_codes_hauppauge_new_table; |
228 | IR_TYPE_RC5, &ir_codes_hauppauge_new_table); | ||
229 | if (error < 0) | ||
230 | goto out2; | ||
231 | 234 | ||
232 | if (rc5_device < 0) | 235 | if (rc5_device < 0) |
233 | budget_ci->ir.rc5_device = 0x1f; | 236 | budget_ci->ir.rc5_device = 0x1f; |
234 | else | ||
235 | budget_ci->ir.rc5_device = rc5_device; | ||
236 | break; | 237 | break; |
237 | case 0x1010: | 238 | case 0x1010: |
238 | case 0x1017: | 239 | case 0x1017: |
239 | case 0x101a: | 240 | case 0x101a: |
240 | /* for the Technotrend 1500 bundled remote */ | 241 | /* for the Technotrend 1500 bundled remote */ |
241 | error = ir_input_init(input_dev, &budget_ci->ir.state, | 242 | ir_codes = &ir_codes_tt_1500_table; |
242 | IR_TYPE_RC5, &ir_codes_tt_1500_table); | ||
243 | if (error < 0) | ||
244 | goto out2; | ||
245 | |||
246 | if (rc5_device < 0) | ||
247 | budget_ci->ir.rc5_device = IR_DEVICE_ANY; | ||
248 | else | ||
249 | budget_ci->ir.rc5_device = rc5_device; | ||
250 | break; | 243 | break; |
251 | default: | 244 | default: |
252 | /* unknown remote */ | 245 | /* unknown remote */ |
253 | error = ir_input_init(input_dev, &budget_ci->ir.state, | 246 | ir_codes = &ir_codes_budget_ci_old_table; |
254 | IR_TYPE_RC5, &ir_codes_budget_ci_old_table); | ||
255 | if (error < 0) | ||
256 | goto out2; | ||
257 | |||
258 | if (rc5_device < 0) | ||
259 | budget_ci->ir.rc5_device = IR_DEVICE_ANY; | ||
260 | else | ||
261 | budget_ci->ir.rc5_device = rc5_device; | ||
262 | break; | 247 | break; |
263 | } | 248 | } |
264 | 249 | ||
250 | ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5); | ||
251 | |||
265 | /* initialise the key-up timeout handler */ | 252 | /* initialise the key-up timeout handler */ |
266 | init_timer(&budget_ci->ir.timer_keyup); | 253 | init_timer(&budget_ci->ir.timer_keyup); |
267 | budget_ci->ir.timer_keyup.function = msp430_ir_keyup; | 254 | budget_ci->ir.timer_keyup.function = msp430_ir_keyup; |
268 | budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; | 255 | budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; |
269 | budget_ci->ir.last_raw = 0xffff; /* An impossible value */ | 256 | budget_ci->ir.last_raw = 0xffff; /* An impossible value */ |
270 | error = input_register_device(input_dev); | 257 | error = ir_input_register(input_dev, ir_codes); |
271 | if (error) { | 258 | if (error) { |
272 | printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); | 259 | printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); |
273 | goto out2; | 260 | return error; |
274 | } | 261 | } |
275 | 262 | ||
276 | /* note: these must be after input_register_device */ | 263 | /* note: these must be after input_register_device */ |
@@ -284,12 +271,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) | |||
284 | saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); | 271 | saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); |
285 | 272 | ||
286 | return 0; | 273 | return 0; |
287 | |||
288 | out2: | ||
289 | ir_input_free(input_dev); | ||
290 | input_free_device(input_dev); | ||
291 | out1: | ||
292 | return error; | ||
293 | } | 274 | } |
294 | 275 | ||
295 | static void msp430_ir_deinit(struct budget_ci *budget_ci) | 276 | static void msp430_ir_deinit(struct budget_ci *budget_ci) |
@@ -304,8 +285,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) | |||
304 | del_timer_sync(&dev->timer); | 285 | del_timer_sync(&dev->timer); |
305 | ir_input_nokey(dev, &budget_ci->ir.state); | 286 | ir_input_nokey(dev, &budget_ci->ir.state); |
306 | 287 | ||
307 | ir_input_free(dev); | 288 | ir_input_unregister(dev); |
308 | input_unregister_device(dev); | ||
309 | } | 289 | } |
310 | 290 | ||
311 | static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) | 291 | static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) |
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 4c2b8a246772..3f40f375981b 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig | |||
@@ -215,13 +215,10 @@ config RADIO_MIROPCM20 | |||
215 | module will be called radio-miropcm20. | 215 | module will be called radio-miropcm20. |
216 | 216 | ||
217 | config RADIO_SF16FMI | 217 | config RADIO_SF16FMI |
218 | tristate "SF16FMI Radio" | 218 | tristate "SF16-FMI/SF16-FMP Radio" |
219 | depends on ISA && VIDEO_V4L2 | 219 | depends on ISA && VIDEO_V4L2 |
220 | ---help--- | 220 | ---help--- |
221 | Choose Y here if you have one of these FM radio cards. If you | 221 | Choose Y here if you have one of these FM radio cards. |
222 | compile the driver into the kernel and your card is not PnP one, you | ||
223 | have to add "sf16fm=<io>" to the kernel command line (I/O address is | ||
224 | 0x284 or 0x384). | ||
225 | 222 | ||
226 | In order to control your radio card, you will need to use programs | 223 | In order to control your radio card, you will need to use programs |
227 | that are compatible with the Video For Linux API. Information on | 224 | that are compatible with the Video For Linux API. Information on |
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 35edee009ba8..5bf4985daede 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c | |||
@@ -268,6 +268,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
268 | { | 268 | { |
269 | struct rtrack *rt = video_drvdata(file); | 269 | struct rtrack *rt = video_drvdata(file); |
270 | 270 | ||
271 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
272 | return -EINVAL; | ||
271 | rt_setfreq(rt, f->frequency); | 273 | rt_setfreq(rt, f->frequency); |
272 | return 0; | 274 | return 0; |
273 | } | 275 | } |
@@ -277,6 +279,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
277 | { | 279 | { |
278 | struct rtrack *rt = video_drvdata(file); | 280 | struct rtrack *rt = video_drvdata(file); |
279 | 281 | ||
282 | if (f->tuner != 0) | ||
283 | return -EINVAL; | ||
280 | f->type = V4L2_TUNER_RADIO; | 284 | f->type = V4L2_TUNER_RADIO; |
281 | f->frequency = rt->curfreq; | 285 | f->frequency = rt->curfreq; |
282 | return 0; | 286 | return 0; |
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 8daf809eb01a..c22311393624 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c | |||
@@ -254,6 +254,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
254 | { | 254 | { |
255 | struct aztech *az = video_drvdata(file); | 255 | struct aztech *az = video_drvdata(file); |
256 | 256 | ||
257 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
258 | return -EINVAL; | ||
257 | az_setfreq(az, f->frequency); | 259 | az_setfreq(az, f->frequency); |
258 | return 0; | 260 | return 0; |
259 | } | 261 | } |
@@ -263,6 +265,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
263 | { | 265 | { |
264 | struct aztech *az = video_drvdata(file); | 266 | struct aztech *az = video_drvdata(file); |
265 | 267 | ||
268 | if (f->tuner != 0) | ||
269 | return -EINVAL; | ||
266 | f->type = V4L2_TUNER_RADIO; | 270 | f->type = V4L2_TUNER_RADIO; |
267 | f->frequency = az->curfreq; | 271 | f->frequency = az->curfreq; |
268 | return 0; | 272 | return 0; |
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index c6cf11661868..000f4d34087c 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c | |||
@@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
240 | { | 240 | { |
241 | struct gemtek_pci *card = video_drvdata(file); | 241 | struct gemtek_pci *card = video_drvdata(file); |
242 | 242 | ||
243 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
244 | return -EINVAL; | ||
243 | if (f->frequency < GEMTEK_PCI_RANGE_LOW || | 245 | if (f->frequency < GEMTEK_PCI_RANGE_LOW || |
244 | f->frequency > GEMTEK_PCI_RANGE_HIGH) | 246 | f->frequency > GEMTEK_PCI_RANGE_HIGH) |
245 | return -EINVAL; | 247 | return -EINVAL; |
@@ -253,6 +255,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
253 | { | 255 | { |
254 | struct gemtek_pci *card = video_drvdata(file); | 256 | struct gemtek_pci *card = video_drvdata(file); |
255 | 257 | ||
258 | if (f->tuner != 0) | ||
259 | return -EINVAL; | ||
256 | f->type = V4L2_TUNER_RADIO; | 260 | f->type = V4L2_TUNER_RADIO; |
257 | f->frequency = card->current_frequency; | 261 | f->frequency = card->current_frequency; |
258 | return 0; | 262 | return 0; |
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 64d737c35acf..f8213b7c8ddc 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c | |||
@@ -200,6 +200,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
200 | { | 200 | { |
201 | struct maestro *dev = video_drvdata(file); | 201 | struct maestro *dev = video_drvdata(file); |
202 | 202 | ||
203 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
204 | return -EINVAL; | ||
203 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | 205 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) |
204 | return -EINVAL; | 206 | return -EINVAL; |
205 | mutex_lock(&dev->lock); | 207 | mutex_lock(&dev->lock); |
@@ -213,6 +215,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
213 | { | 215 | { |
214 | struct maestro *dev = video_drvdata(file); | 216 | struct maestro *dev = video_drvdata(file); |
215 | 217 | ||
218 | if (f->tuner != 0) | ||
219 | return -EINVAL; | ||
216 | f->type = V4L2_TUNER_RADIO; | 220 | f->type = V4L2_TUNER_RADIO; |
217 | mutex_lock(&dev->lock); | 221 | mutex_lock(&dev->lock); |
218 | f->frequency = BITS2FREQ(radio_bits_get(dev)); | 222 | f->frequency = BITS2FREQ(radio_bits_get(dev)); |
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 3da51fe8fb93..44b4dbedb322 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c | |||
@@ -262,6 +262,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
262 | { | 262 | { |
263 | struct maxiradio *dev = video_drvdata(file); | 263 | struct maxiradio *dev = video_drvdata(file); |
264 | 264 | ||
265 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
266 | return -EINVAL; | ||
265 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { | 267 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { |
266 | dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", | 268 | dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", |
267 | f->frequency / 16000, | 269 | f->frequency / 16000, |
@@ -285,6 +287,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
285 | { | 287 | { |
286 | struct maxiradio *dev = video_drvdata(file); | 288 | struct maxiradio *dev = video_drvdata(file); |
287 | 289 | ||
290 | if (f->tuner != 0) | ||
291 | return -EINVAL; | ||
288 | f->type = V4L2_TUNER_RADIO; | 292 | f->type = V4L2_TUNER_RADIO; |
289 | f->frequency = dev->freq; | 293 | f->frequency = dev->freq; |
290 | 294 | ||
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 949f60513d9e..02a9cefc9a00 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c | |||
@@ -374,6 +374,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
374 | { | 374 | { |
375 | struct amradio_device *radio = file->private_data; | 375 | struct amradio_device *radio = file->private_data; |
376 | 376 | ||
377 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
378 | return -EINVAL; | ||
377 | return amradio_setfreq(radio, f->frequency); | 379 | return amradio_setfreq(radio, f->frequency); |
378 | } | 380 | } |
379 | 381 | ||
@@ -383,6 +385,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
383 | { | 385 | { |
384 | struct amradio_device *radio = file->private_data; | 386 | struct amradio_device *radio = file->private_data; |
385 | 387 | ||
388 | if (f->tuner != 0) | ||
389 | return -EINVAL; | ||
386 | f->type = V4L2_TUNER_RADIO; | 390 | f->type = V4L2_TUNER_RADIO; |
387 | f->frequency = radio->curfreq; | 391 | f->frequency = radio->curfreq; |
388 | 392 | ||
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 9cb193fa6e33..a79296aac9a9 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c | |||
@@ -167,6 +167,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
167 | { | 167 | { |
168 | struct rtrack2 *rt = video_drvdata(file); | 168 | struct rtrack2 *rt = video_drvdata(file); |
169 | 169 | ||
170 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
171 | return -EINVAL; | ||
170 | rt_setfreq(rt, f->frequency); | 172 | rt_setfreq(rt, f->frequency); |
171 | return 0; | 173 | return 0; |
172 | } | 174 | } |
@@ -176,6 +178,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
176 | { | 178 | { |
177 | struct rtrack2 *rt = video_drvdata(file); | 179 | struct rtrack2 *rt = video_drvdata(file); |
178 | 180 | ||
181 | if (f->tuner != 0) | ||
182 | return -EINVAL; | ||
179 | f->type = V4L2_TUNER_RADIO; | 183 | f->type = V4L2_TUNER_RADIO; |
180 | f->frequency = rt->curfreq; | 184 | f->frequency = rt->curfreq; |
181 | return 0; | 185 | return 0; |
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 49c4aab95dab..985359d18aa5 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* SF16FMI radio driver for Linux radio support | 1 | /* SF16-FMI and SF16-FMP radio driver for Linux radio support |
2 | * heavily based on rtrack driver... | 2 | * heavily based on rtrack driver... |
3 | * (c) 1997 M. Kirkwood | 3 | * (c) 1997 M. Kirkwood |
4 | * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz | 4 | * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz |
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); | 12 | * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); |
13 | * No volume control - only mute/unmute - you have to use line volume | 13 | * No volume control - only mute/unmute - you have to use line volume |
14 | * control on SB-part of SF16FMI | 14 | * control on SB-part of SF16-FMI/SF16-FMP |
15 | * | 15 | * |
16 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> | 16 | * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
17 | */ | 17 | */ |
@@ -30,14 +30,14 @@ | |||
30 | #include <media/v4l2-ioctl.h> | 30 | #include <media/v4l2-ioctl.h> |
31 | 31 | ||
32 | MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); | 32 | MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); |
33 | MODULE_DESCRIPTION("A driver for the SF16MI radio."); | 33 | MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio."); |
34 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
35 | 35 | ||
36 | static int io = -1; | 36 | static int io = -1; |
37 | static int radio_nr = -1; | 37 | static int radio_nr = -1; |
38 | 38 | ||
39 | module_param(io, int, 0); | 39 | module_param(io, int, 0); |
40 | MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); | 40 | MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)"); |
41 | module_param(radio_nr, int, 0); | 41 | module_param(radio_nr, int, 0); |
42 | 42 | ||
43 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) | 43 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) |
@@ -47,13 +47,14 @@ struct fmi | |||
47 | struct v4l2_device v4l2_dev; | 47 | struct v4l2_device v4l2_dev; |
48 | struct video_device vdev; | 48 | struct video_device vdev; |
49 | int io; | 49 | int io; |
50 | int curvol; /* 1 or 0 */ | 50 | bool mute; |
51 | unsigned long curfreq; /* freq in kHz */ | 51 | unsigned long curfreq; /* freq in kHz */ |
52 | struct mutex lock; | 52 | struct mutex lock; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static struct fmi fmi_card; | 55 | static struct fmi fmi_card; |
56 | static struct pnp_dev *dev; | 56 | static struct pnp_dev *dev; |
57 | bool pnp_attached; | ||
57 | 58 | ||
58 | /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ | 59 | /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ |
59 | /* It is only useful to give freq in interval of 800 (=0.05Mhz), | 60 | /* It is only useful to give freq in interval of 800 (=0.05Mhz), |
@@ -105,7 +106,7 @@ static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) | |||
105 | outbits(8, 0xC0, fmi->io); | 106 | outbits(8, 0xC0, fmi->io); |
106 | msleep(143); /* was schedule_timeout(HZ/7) */ | 107 | msleep(143); /* was schedule_timeout(HZ/7) */ |
107 | mutex_unlock(&fmi->lock); | 108 | mutex_unlock(&fmi->lock); |
108 | if (fmi->curvol) | 109 | if (!fmi->mute) |
109 | fmi_unmute(fmi); | 110 | fmi_unmute(fmi); |
110 | return 0; | 111 | return 0; |
111 | } | 112 | } |
@@ -116,7 +117,7 @@ static inline int fmi_getsigstr(struct fmi *fmi) | |||
116 | int res; | 117 | int res; |
117 | 118 | ||
118 | mutex_lock(&fmi->lock); | 119 | mutex_lock(&fmi->lock); |
119 | val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */ | 120 | val = fmi->mute ? 0x00 : 0x08; /* mute/unmute */ |
120 | outb(val, fmi->io); | 121 | outb(val, fmi->io); |
121 | outb(val | 0x10, fmi->io); | 122 | outb(val | 0x10, fmi->io); |
122 | msleep(143); /* was schedule_timeout(HZ/7) */ | 123 | msleep(143); /* was schedule_timeout(HZ/7) */ |
@@ -168,6 +169,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
168 | { | 169 | { |
169 | struct fmi *fmi = video_drvdata(file); | 170 | struct fmi *fmi = video_drvdata(file); |
170 | 171 | ||
172 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
173 | return -EINVAL; | ||
171 | if (f->frequency < RSF16_MINFREQ || | 174 | if (f->frequency < RSF16_MINFREQ || |
172 | f->frequency > RSF16_MAXFREQ) | 175 | f->frequency > RSF16_MAXFREQ) |
173 | return -EINVAL; | 176 | return -EINVAL; |
@@ -182,6 +185,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
182 | { | 185 | { |
183 | struct fmi *fmi = video_drvdata(file); | 186 | struct fmi *fmi = video_drvdata(file); |
184 | 187 | ||
188 | if (f->tuner != 0) | ||
189 | return -EINVAL; | ||
185 | f->type = V4L2_TUNER_RADIO; | 190 | f->type = V4L2_TUNER_RADIO; |
186 | f->frequency = fmi->curfreq; | 191 | f->frequency = fmi->curfreq; |
187 | return 0; | 192 | return 0; |
@@ -204,7 +209,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
204 | 209 | ||
205 | switch (ctrl->id) { | 210 | switch (ctrl->id) { |
206 | case V4L2_CID_AUDIO_MUTE: | 211 | case V4L2_CID_AUDIO_MUTE: |
207 | ctrl->value = fmi->curvol; | 212 | ctrl->value = fmi->mute; |
208 | return 0; | 213 | return 0; |
209 | } | 214 | } |
210 | return -EINVAL; | 215 | return -EINVAL; |
@@ -221,7 +226,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
221 | fmi_mute(fmi); | 226 | fmi_mute(fmi); |
222 | else | 227 | else |
223 | fmi_unmute(fmi); | 228 | fmi_unmute(fmi); |
224 | fmi->curvol = ctrl->value; | 229 | fmi->mute = ctrl->value; |
225 | return 0; | 230 | return 0; |
226 | } | 231 | } |
227 | return -EINVAL; | 232 | return -EINVAL; |
@@ -316,26 +321,54 @@ static int __init fmi_init(void) | |||
316 | { | 321 | { |
317 | struct fmi *fmi = &fmi_card; | 322 | struct fmi *fmi = &fmi_card; |
318 | struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; | 323 | struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; |
319 | int res; | 324 | int res, i; |
325 | int probe_ports[] = { 0, 0x284, 0x384 }; | ||
326 | |||
327 | if (io < 0) { | ||
328 | for (i = 0; i < ARRAY_SIZE(probe_ports); i++) { | ||
329 | io = probe_ports[i]; | ||
330 | if (io == 0) { | ||
331 | io = isapnp_fmi_probe(); | ||
332 | if (io < 0) | ||
333 | continue; | ||
334 | pnp_attached = 1; | ||
335 | } | ||
336 | if (!request_region(io, 2, "radio-sf16fmi")) { | ||
337 | if (pnp_attached) | ||
338 | pnp_device_detach(dev); | ||
339 | io = -1; | ||
340 | continue; | ||
341 | } | ||
342 | if (pnp_attached || | ||
343 | ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0)) | ||
344 | break; | ||
345 | release_region(io, 2); | ||
346 | io = -1; | ||
347 | } | ||
348 | } else { | ||
349 | if (!request_region(io, 2, "radio-sf16fmi")) { | ||
350 | printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io); | ||
351 | return -EBUSY; | ||
352 | } | ||
353 | if (inb(io) == 0xff) { | ||
354 | printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io); | ||
355 | release_region(io, 2); | ||
356 | return -ENODEV; | ||
357 | } | ||
358 | } | ||
359 | if (io < 0) { | ||
360 | printk(KERN_ERR "radio-sf16fmi: no cards found\n"); | ||
361 | return -ENODEV; | ||
362 | } | ||
320 | 363 | ||
321 | if (io < 0) | ||
322 | io = isapnp_fmi_probe(); | ||
323 | strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); | 364 | strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); |
324 | fmi->io = io; | 365 | fmi->io = io; |
325 | if (fmi->io < 0) { | ||
326 | v4l2_err(v4l2_dev, "No PnP card found.\n"); | ||
327 | return fmi->io; | ||
328 | } | ||
329 | if (!request_region(io, 2, "radio-sf16fmi")) { | ||
330 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io); | ||
331 | pnp_device_detach(dev); | ||
332 | return -EBUSY; | ||
333 | } | ||
334 | 366 | ||
335 | res = v4l2_device_register(NULL, v4l2_dev); | 367 | res = v4l2_device_register(NULL, v4l2_dev); |
336 | if (res < 0) { | 368 | if (res < 0) { |
337 | release_region(fmi->io, 2); | 369 | release_region(fmi->io, 2); |
338 | pnp_device_detach(dev); | 370 | if (pnp_attached) |
371 | pnp_device_detach(dev); | ||
339 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | 372 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); |
340 | return res; | 373 | return res; |
341 | } | 374 | } |
@@ -352,7 +385,8 @@ static int __init fmi_init(void) | |||
352 | if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | 385 | if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { |
353 | v4l2_device_unregister(v4l2_dev); | 386 | v4l2_device_unregister(v4l2_dev); |
354 | release_region(fmi->io, 2); | 387 | release_region(fmi->io, 2); |
355 | pnp_device_detach(dev); | 388 | if (pnp_attached) |
389 | pnp_device_detach(dev); | ||
356 | return -EINVAL; | 390 | return -EINVAL; |
357 | } | 391 | } |
358 | 392 | ||
@@ -369,7 +403,7 @@ static void __exit fmi_exit(void) | |||
369 | video_unregister_device(&fmi->vdev); | 403 | video_unregister_device(&fmi->vdev); |
370 | v4l2_device_unregister(&fmi->v4l2_dev); | 404 | v4l2_device_unregister(&fmi->v4l2_dev); |
371 | release_region(fmi->io, 2); | 405 | release_region(fmi->io, 2); |
372 | if (dev) | 406 | if (dev && pnp_attached) |
373 | pnp_device_detach(dev); | 407 | pnp_device_detach(dev); |
374 | } | 408 | } |
375 | 409 | ||
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index a11414f648d4..52c7bbb32b8b 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c | |||
@@ -251,6 +251,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
251 | { | 251 | { |
252 | struct fmr2 *fmr2 = video_drvdata(file); | 252 | struct fmr2 *fmr2 = video_drvdata(file); |
253 | 253 | ||
254 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
255 | return -EINVAL; | ||
254 | if (f->frequency < RSF16_MINFREQ || | 256 | if (f->frequency < RSF16_MINFREQ || |
255 | f->frequency > RSF16_MAXFREQ) | 257 | f->frequency > RSF16_MAXFREQ) |
256 | return -EINVAL; | 258 | return -EINVAL; |
@@ -272,6 +274,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
272 | { | 274 | { |
273 | struct fmr2 *fmr2 = video_drvdata(file); | 275 | struct fmr2 *fmr2 = video_drvdata(file); |
274 | 276 | ||
277 | if (f->tuner != 0) | ||
278 | return -EINVAL; | ||
275 | f->type = V4L2_TUNER_RADIO; | 279 | f->type = V4L2_TUNER_RADIO; |
276 | f->frequency = fmr2->curfreq; | 280 | f->frequency = fmr2->curfreq; |
277 | return 0; | 281 | return 0; |
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 3cd76dddb6aa..8e718bfcdad3 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c | |||
@@ -314,7 +314,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
314 | if (v->index > 0) | 314 | if (v->index > 0) |
315 | return -EINVAL; | 315 | return -EINVAL; |
316 | 316 | ||
317 | memset(v, 0, sizeof(v)); | 317 | memset(v, 0, sizeof(*v)); |
318 | strcpy(v->name, "FM"); | 318 | strcpy(v->name, "FM"); |
319 | v->type = V4L2_TUNER_RADIO; | 319 | v->type = V4L2_TUNER_RADIO; |
320 | tea5764_i2c_read(radio); | 320 | tea5764_i2c_read(radio); |
@@ -349,7 +349,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
349 | { | 349 | { |
350 | struct tea5764_device *radio = video_drvdata(file); | 350 | struct tea5764_device *radio = video_drvdata(file); |
351 | 351 | ||
352 | if (f->tuner != 0) | 352 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) |
353 | return -EINVAL; | 353 | return -EINVAL; |
354 | if (f->frequency == 0) { | 354 | if (f->frequency == 0) { |
355 | /* We special case this as a power down control. */ | 355 | /* We special case this as a power down control. */ |
@@ -370,8 +370,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
370 | struct tea5764_device *radio = video_drvdata(file); | 370 | struct tea5764_device *radio = video_drvdata(file); |
371 | struct tea5764_regs *r = &radio->regs; | 371 | struct tea5764_regs *r = &radio->regs; |
372 | 372 | ||
373 | if (f->tuner != 0) | ||
374 | return -EINVAL; | ||
373 | tea5764_i2c_read(radio); | 375 | tea5764_i2c_read(radio); |
374 | memset(f, 0, sizeof(f)); | 376 | memset(f, 0, sizeof(*f)); |
375 | f->type = V4L2_TUNER_RADIO; | 377 | f->type = V4L2_TUNER_RADIO; |
376 | if (r->tnctrl & TEA5764_TNCTRL_PUPD0) | 378 | if (r->tnctrl & TEA5764_TNCTRL_PUPD0) |
377 | f->frequency = (tea5764_get_freq(radio) * 2) / 125; | 379 | f->frequency = (tea5764_get_freq(radio) * 2) / 125; |
@@ -458,12 +460,8 @@ static int vidioc_s_audio(struct file *file, void *priv, | |||
458 | static int tea5764_open(struct file *file) | 460 | static int tea5764_open(struct file *file) |
459 | { | 461 | { |
460 | /* Currently we support only one device */ | 462 | /* Currently we support only one device */ |
461 | int minor = video_devdata(file)->minor; | ||
462 | struct tea5764_device *radio = video_drvdata(file); | 463 | struct tea5764_device *radio = video_drvdata(file); |
463 | 464 | ||
464 | if (radio->videodev->minor != minor) | ||
465 | return -ENODEV; | ||
466 | |||
467 | mutex_lock(&radio->mutex); | 465 | mutex_lock(&radio->mutex); |
468 | /* Only exclusive access */ | 466 | /* Only exclusive access */ |
469 | if (radio->users) { | 467 | if (radio->users) { |
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 699db9acaaf7..fc1c860fd438 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c | |||
@@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
240 | { | 240 | { |
241 | struct terratec *tt = video_drvdata(file); | 241 | struct terratec *tt = video_drvdata(file); |
242 | 242 | ||
243 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
244 | return -EINVAL; | ||
243 | tt_setfreq(tt, f->frequency); | 245 | tt_setfreq(tt, f->frequency); |
244 | return 0; | 246 | return 0; |
245 | } | 247 | } |
@@ -249,6 +251,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
249 | { | 251 | { |
250 | struct terratec *tt = video_drvdata(file); | 252 | struct terratec *tt = video_drvdata(file); |
251 | 253 | ||
254 | if (f->tuner != 0) | ||
255 | return -EINVAL; | ||
252 | f->type = V4L2_TUNER_RADIO; | 256 | f->type = V4L2_TUNER_RADIO; |
253 | f->frequency = tt->curfreq; | 257 | f->frequency = tt->curfreq; |
254 | return 0; | 258 | return 0; |
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 6f9ecc359356..9d6dcf8af5b0 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c | |||
@@ -239,6 +239,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
239 | { | 239 | { |
240 | struct trust *tr = video_drvdata(file); | 240 | struct trust *tr = video_drvdata(file); |
241 | 241 | ||
242 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
243 | return -EINVAL; | ||
242 | tr_setfreq(tr, f->frequency); | 244 | tr_setfreq(tr, f->frequency); |
243 | return 0; | 245 | return 0; |
244 | } | 246 | } |
@@ -248,6 +250,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
248 | { | 250 | { |
249 | struct trust *tr = video_drvdata(file); | 251 | struct trust *tr = video_drvdata(file); |
250 | 252 | ||
253 | if (f->tuner != 0) | ||
254 | return -EINVAL; | ||
251 | f->type = V4L2_TUNER_RADIO; | 255 | f->type = V4L2_TUNER_RADIO; |
252 | f->frequency = tr->curfreq; | 256 | f->frequency = tr->curfreq; |
253 | return 0; | 257 | return 0; |
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 3a98f1399495..03439282dfce 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c | |||
@@ -207,6 +207,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
207 | { | 207 | { |
208 | struct typhoon *dev = video_drvdata(file); | 208 | struct typhoon *dev = video_drvdata(file); |
209 | 209 | ||
210 | if (f->tuner != 0) | ||
211 | return -EINVAL; | ||
210 | f->type = V4L2_TUNER_RADIO; | 212 | f->type = V4L2_TUNER_RADIO; |
211 | f->frequency = dev->curfreq; | 213 | f->frequency = dev->curfreq; |
212 | return 0; | 214 | return 0; |
@@ -217,6 +219,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
217 | { | 219 | { |
218 | struct typhoon *dev = video_drvdata(file); | 220 | struct typhoon *dev = video_drvdata(file); |
219 | 221 | ||
222 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
223 | return -EINVAL; | ||
220 | dev->curfreq = f->frequency; | 224 | dev->curfreq = f->frequency; |
221 | typhoon_setfreq(dev, dev->curfreq); | 225 | typhoon_setfreq(dev, dev->curfreq); |
222 | return 0; | 226 | return 0; |
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 80e98b6422fe..f31eab99c943 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c | |||
@@ -266,6 +266,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
266 | { | 266 | { |
267 | struct zoltrix *zol = video_drvdata(file); | 267 | struct zoltrix *zol = video_drvdata(file); |
268 | 268 | ||
269 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | ||
270 | return -EINVAL; | ||
269 | if (zol_setfreq(zol, f->frequency) != 0) | 271 | if (zol_setfreq(zol, f->frequency) != 0) |
270 | return -EINVAL; | 272 | return -EINVAL; |
271 | return 0; | 273 | return 0; |
@@ -276,6 +278,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
276 | { | 278 | { |
277 | struct zoltrix *zol = video_drvdata(file); | 279 | struct zoltrix *zol = video_drvdata(file); |
278 | 280 | ||
281 | if (f->tuner != 0) | ||
282 | return -EINVAL; | ||
279 | f->type = V4L2_TUNER_RADIO; | 283 | f->type = V4L2_TUNER_RADIO; |
280 | f->frequency = zol->curfreq; | 284 | f->frequency = zol->curfreq; |
281 | return 0; | 285 | return 0; |
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index f33315f2c543..4da0f150c6e2 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c | |||
@@ -426,6 +426,104 @@ int si470x_rds_on(struct si470x_device *radio) | |||
426 | 426 | ||
427 | 427 | ||
428 | /************************************************************************** | 428 | /************************************************************************** |
429 | * File Operations Interface | ||
430 | **************************************************************************/ | ||
431 | |||
432 | /* | ||
433 | * si470x_fops_read - read RDS data | ||
434 | */ | ||
435 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
436 | size_t count, loff_t *ppos) | ||
437 | { | ||
438 | struct si470x_device *radio = video_drvdata(file); | ||
439 | int retval = 0; | ||
440 | unsigned int block_count = 0; | ||
441 | |||
442 | /* switch on rds reception */ | ||
443 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
444 | si470x_rds_on(radio); | ||
445 | |||
446 | /* block if no new data available */ | ||
447 | while (radio->wr_index == radio->rd_index) { | ||
448 | if (file->f_flags & O_NONBLOCK) { | ||
449 | retval = -EWOULDBLOCK; | ||
450 | goto done; | ||
451 | } | ||
452 | if (wait_event_interruptible(radio->read_queue, | ||
453 | radio->wr_index != radio->rd_index) < 0) { | ||
454 | retval = -EINTR; | ||
455 | goto done; | ||
456 | } | ||
457 | } | ||
458 | |||
459 | /* calculate block count from byte count */ | ||
460 | count /= 3; | ||
461 | |||
462 | /* copy RDS block out of internal buffer and to user buffer */ | ||
463 | mutex_lock(&radio->lock); | ||
464 | while (block_count < count) { | ||
465 | if (radio->rd_index == radio->wr_index) | ||
466 | break; | ||
467 | |||
468 | /* always transfer rds complete blocks */ | ||
469 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | ||
470 | /* retval = -EFAULT; */ | ||
471 | break; | ||
472 | |||
473 | /* increment and wrap read pointer */ | ||
474 | radio->rd_index += 3; | ||
475 | if (radio->rd_index >= radio->buf_size) | ||
476 | radio->rd_index = 0; | ||
477 | |||
478 | /* increment counters */ | ||
479 | block_count++; | ||
480 | buf += 3; | ||
481 | retval += 3; | ||
482 | } | ||
483 | mutex_unlock(&radio->lock); | ||
484 | |||
485 | done: | ||
486 | return retval; | ||
487 | } | ||
488 | |||
489 | |||
490 | /* | ||
491 | * si470x_fops_poll - poll RDS data | ||
492 | */ | ||
493 | static unsigned int si470x_fops_poll(struct file *file, | ||
494 | struct poll_table_struct *pts) | ||
495 | { | ||
496 | struct si470x_device *radio = video_drvdata(file); | ||
497 | int retval = 0; | ||
498 | |||
499 | /* switch on rds reception */ | ||
500 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
501 | si470x_rds_on(radio); | ||
502 | |||
503 | poll_wait(file, &radio->read_queue, pts); | ||
504 | |||
505 | if (radio->rd_index != radio->wr_index) | ||
506 | retval = POLLIN | POLLRDNORM; | ||
507 | |||
508 | return retval; | ||
509 | } | ||
510 | |||
511 | |||
512 | /* | ||
513 | * si470x_fops - file operations interface | ||
514 | */ | ||
515 | static const struct v4l2_file_operations si470x_fops = { | ||
516 | .owner = THIS_MODULE, | ||
517 | .read = si470x_fops_read, | ||
518 | .poll = si470x_fops_poll, | ||
519 | .ioctl = video_ioctl2, | ||
520 | .open = si470x_fops_open, | ||
521 | .release = si470x_fops_release, | ||
522 | }; | ||
523 | |||
524 | |||
525 | |||
526 | /************************************************************************** | ||
429 | * Video4Linux Interface | 527 | * Video4Linux Interface |
430 | **************************************************************************/ | 528 | **************************************************************************/ |
431 | 529 | ||
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2d53b6a9409b..5466015346a1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c | |||
@@ -22,22 +22,17 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | 24 | ||
25 | /* | ||
26 | * ToDo: | ||
27 | * - RDS support | ||
28 | */ | ||
29 | |||
30 | |||
31 | /* driver definitions */ | 25 | /* driver definitions */ |
32 | #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; | 26 | #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; |
33 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0) | 27 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) |
34 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | 28 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" |
35 | #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" | 29 | #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" |
36 | #define DRIVER_VERSION "1.0.0" | 30 | #define DRIVER_VERSION "1.0.1" |
37 | 31 | ||
38 | /* kernel includes */ | 32 | /* kernel includes */ |
39 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
40 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/interrupt.h> | ||
41 | 36 | ||
42 | #include "radio-si470x.h" | 37 | #include "radio-si470x.h" |
43 | 38 | ||
@@ -62,6 +57,20 @@ static int radio_nr = -1; | |||
62 | module_param(radio_nr, int, 0444); | 57 | module_param(radio_nr, int, 0444); |
63 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); | 58 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); |
64 | 59 | ||
60 | /* RDS buffer blocks */ | ||
61 | static unsigned int rds_buf = 100; | ||
62 | module_param(rds_buf, uint, 0444); | ||
63 | MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); | ||
64 | |||
65 | /* RDS maximum block errors */ | ||
66 | static unsigned short max_rds_errors = 1; | ||
67 | /* 0 means 0 errors requiring correction */ | ||
68 | /* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ | ||
69 | /* 2 means 3-5 errors requiring correction */ | ||
70 | /* 3 means 6+ errors or errors in checkword, correction not possible */ | ||
71 | module_param(max_rds_errors, ushort, 0644); | ||
72 | MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | ||
73 | |||
65 | 74 | ||
66 | 75 | ||
67 | /************************************************************************** | 76 | /************************************************************************** |
@@ -173,7 +182,7 @@ int si470x_disconnect_check(struct si470x_device *radio) | |||
173 | /* | 182 | /* |
174 | * si470x_fops_open - file open | 183 | * si470x_fops_open - file open |
175 | */ | 184 | */ |
176 | static int si470x_fops_open(struct file *file) | 185 | int si470x_fops_open(struct file *file) |
177 | { | 186 | { |
178 | struct si470x_device *radio = video_drvdata(file); | 187 | struct si470x_device *radio = video_drvdata(file); |
179 | int retval = 0; | 188 | int retval = 0; |
@@ -181,12 +190,21 @@ static int si470x_fops_open(struct file *file) | |||
181 | mutex_lock(&radio->lock); | 190 | mutex_lock(&radio->lock); |
182 | radio->users++; | 191 | radio->users++; |
183 | 192 | ||
184 | if (radio->users == 1) | 193 | if (radio->users == 1) { |
185 | /* start radio */ | 194 | /* start radio */ |
186 | retval = si470x_start(radio); | 195 | retval = si470x_start(radio); |
196 | if (retval < 0) | ||
197 | goto done; | ||
198 | |||
199 | /* enable RDS interrupt */ | ||
200 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; | ||
201 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; | ||
202 | radio->registers[SYSCONFIG1] |= 0x1 << 2; | ||
203 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
204 | } | ||
187 | 205 | ||
206 | done: | ||
188 | mutex_unlock(&radio->lock); | 207 | mutex_unlock(&radio->lock); |
189 | |||
190 | return retval; | 208 | return retval; |
191 | } | 209 | } |
192 | 210 | ||
@@ -194,7 +212,7 @@ static int si470x_fops_open(struct file *file) | |||
194 | /* | 212 | /* |
195 | * si470x_fops_release - file release | 213 | * si470x_fops_release - file release |
196 | */ | 214 | */ |
197 | static int si470x_fops_release(struct file *file) | 215 | int si470x_fops_release(struct file *file) |
198 | { | 216 | { |
199 | struct si470x_device *radio = video_drvdata(file); | 217 | struct si470x_device *radio = video_drvdata(file); |
200 | int retval = 0; | 218 | int retval = 0; |
@@ -215,17 +233,6 @@ static int si470x_fops_release(struct file *file) | |||
215 | } | 233 | } |
216 | 234 | ||
217 | 235 | ||
218 | /* | ||
219 | * si470x_fops - file operations interface | ||
220 | */ | ||
221 | const struct v4l2_file_operations si470x_fops = { | ||
222 | .owner = THIS_MODULE, | ||
223 | .ioctl = video_ioctl2, | ||
224 | .open = si470x_fops_open, | ||
225 | .release = si470x_fops_release, | ||
226 | }; | ||
227 | |||
228 | |||
229 | 236 | ||
230 | /************************************************************************** | 237 | /************************************************************************** |
231 | * Video4Linux Interface | 238 | * Video4Linux Interface |
@@ -253,6 +260,105 @@ int si470x_vidioc_querycap(struct file *file, void *priv, | |||
253 | **************************************************************************/ | 260 | **************************************************************************/ |
254 | 261 | ||
255 | /* | 262 | /* |
263 | * si470x_i2c_interrupt_work - rds processing function | ||
264 | */ | ||
265 | static void si470x_i2c_interrupt_work(struct work_struct *work) | ||
266 | { | ||
267 | struct si470x_device *radio = container_of(work, | ||
268 | struct si470x_device, radio_work); | ||
269 | unsigned char regnr; | ||
270 | unsigned char blocknum; | ||
271 | unsigned short bler; /* rds block errors */ | ||
272 | unsigned short rds; | ||
273 | unsigned char tmpbuf[3]; | ||
274 | int retval = 0; | ||
275 | |||
276 | /* safety checks */ | ||
277 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
278 | return; | ||
279 | |||
280 | /* Update RDS registers */ | ||
281 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { | ||
282 | retval = si470x_get_register(radio, STATUSRSSI + regnr); | ||
283 | if (retval < 0) | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /* get rds blocks */ | ||
288 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) | ||
289 | /* No RDS group ready, better luck next time */ | ||
290 | return; | ||
291 | |||
292 | for (blocknum = 0; blocknum < 4; blocknum++) { | ||
293 | switch (blocknum) { | ||
294 | default: | ||
295 | bler = (radio->registers[STATUSRSSI] & | ||
296 | STATUSRSSI_BLERA) >> 9; | ||
297 | rds = radio->registers[RDSA]; | ||
298 | break; | ||
299 | case 1: | ||
300 | bler = (radio->registers[READCHAN] & | ||
301 | READCHAN_BLERB) >> 14; | ||
302 | rds = radio->registers[RDSB]; | ||
303 | break; | ||
304 | case 2: | ||
305 | bler = (radio->registers[READCHAN] & | ||
306 | READCHAN_BLERC) >> 12; | ||
307 | rds = radio->registers[RDSC]; | ||
308 | break; | ||
309 | case 3: | ||
310 | bler = (radio->registers[READCHAN] & | ||
311 | READCHAN_BLERD) >> 10; | ||
312 | rds = radio->registers[RDSD]; | ||
313 | break; | ||
314 | }; | ||
315 | |||
316 | /* Fill the V4L2 RDS buffer */ | ||
317 | put_unaligned_le16(rds, &tmpbuf); | ||
318 | tmpbuf[2] = blocknum; /* offset name */ | ||
319 | tmpbuf[2] |= blocknum << 3; /* received offset */ | ||
320 | if (bler > max_rds_errors) | ||
321 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | ||
322 | else if (bler > 0) | ||
323 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | ||
324 | |||
325 | /* copy RDS block to internal buffer */ | ||
326 | memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); | ||
327 | radio->wr_index += 3; | ||
328 | |||
329 | /* wrap write pointer */ | ||
330 | if (radio->wr_index >= radio->buf_size) | ||
331 | radio->wr_index = 0; | ||
332 | |||
333 | /* check for overflow */ | ||
334 | if (radio->wr_index == radio->rd_index) { | ||
335 | /* increment and wrap read pointer */ | ||
336 | radio->rd_index += 3; | ||
337 | if (radio->rd_index >= radio->buf_size) | ||
338 | radio->rd_index = 0; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | if (radio->wr_index != radio->rd_index) | ||
343 | wake_up_interruptible(&radio->read_queue); | ||
344 | } | ||
345 | |||
346 | |||
347 | /* | ||
348 | * si470x_i2c_interrupt - interrupt handler | ||
349 | */ | ||
350 | static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) | ||
351 | { | ||
352 | struct si470x_device *radio = dev_id; | ||
353 | |||
354 | if (!work_pending(&radio->radio_work)) | ||
355 | schedule_work(&radio->radio_work); | ||
356 | |||
357 | return IRQ_HANDLED; | ||
358 | } | ||
359 | |||
360 | |||
361 | /* | ||
256 | * si470x_i2c_probe - probe for the device | 362 | * si470x_i2c_probe - probe for the device |
257 | */ | 363 | */ |
258 | static int __devinit si470x_i2c_probe(struct i2c_client *client, | 364 | static int __devinit si470x_i2c_probe(struct i2c_client *client, |
@@ -268,6 +374,8 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
268 | retval = -ENOMEM; | 374 | retval = -ENOMEM; |
269 | goto err_initial; | 375 | goto err_initial; |
270 | } | 376 | } |
377 | |||
378 | INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work); | ||
271 | radio->users = 0; | 379 | radio->users = 0; |
272 | radio->client = client; | 380 | radio->client = client; |
273 | mutex_init(&radio->lock); | 381 | mutex_init(&radio->lock); |
@@ -319,6 +427,26 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
319 | /* set initial frequency */ | 427 | /* set initial frequency */ |
320 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | 428 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ |
321 | 429 | ||
430 | /* rds buffer allocation */ | ||
431 | radio->buf_size = rds_buf * 3; | ||
432 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | ||
433 | if (!radio->buffer) { | ||
434 | retval = -EIO; | ||
435 | goto err_video; | ||
436 | } | ||
437 | |||
438 | /* rds buffer configuration */ | ||
439 | radio->wr_index = 0; | ||
440 | radio->rd_index = 0; | ||
441 | init_waitqueue_head(&radio->read_queue); | ||
442 | |||
443 | retval = request_irq(client->irq, si470x_i2c_interrupt, | ||
444 | IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); | ||
445 | if (retval) { | ||
446 | dev_err(&client->dev, "Failed to register interrupt\n"); | ||
447 | goto err_rds; | ||
448 | } | ||
449 | |||
322 | /* register video device */ | 450 | /* register video device */ |
323 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, | 451 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, |
324 | radio_nr); | 452 | radio_nr); |
@@ -330,6 +458,9 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
330 | 458 | ||
331 | return 0; | 459 | return 0; |
332 | err_all: | 460 | err_all: |
461 | free_irq(client->irq, radio); | ||
462 | err_rds: | ||
463 | kfree(radio->buffer); | ||
333 | err_video: | 464 | err_video: |
334 | video_device_release(radio->videodev); | 465 | video_device_release(radio->videodev); |
335 | err_radio: | 466 | err_radio: |
@@ -346,6 +477,8 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) | |||
346 | { | 477 | { |
347 | struct si470x_device *radio = i2c_get_clientdata(client); | 478 | struct si470x_device *radio = i2c_get_clientdata(client); |
348 | 479 | ||
480 | free_irq(client->irq, radio); | ||
481 | cancel_work_sync(&radio->radio_work); | ||
349 | video_unregister_device(radio->videodev); | 482 | video_unregister_device(radio->videodev); |
350 | kfree(radio); | 483 | kfree(radio); |
351 | i2c_set_clientdata(client, NULL); | 484 | i2c_set_clientdata(client, NULL); |
@@ -354,6 +487,44 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) | |||
354 | } | 487 | } |
355 | 488 | ||
356 | 489 | ||
490 | #ifdef CONFIG_PM | ||
491 | /* | ||
492 | * si470x_i2c_suspend - suspend the device | ||
493 | */ | ||
494 | static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg) | ||
495 | { | ||
496 | struct si470x_device *radio = i2c_get_clientdata(client); | ||
497 | |||
498 | /* power down */ | ||
499 | radio->registers[POWERCFG] |= POWERCFG_DISABLE; | ||
500 | if (si470x_set_register(radio, POWERCFG) < 0) | ||
501 | return -EIO; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | |||
507 | /* | ||
508 | * si470x_i2c_resume - resume the device | ||
509 | */ | ||
510 | static int si470x_i2c_resume(struct i2c_client *client) | ||
511 | { | ||
512 | struct si470x_device *radio = i2c_get_clientdata(client); | ||
513 | |||
514 | /* power up : need 110ms */ | ||
515 | radio->registers[POWERCFG] |= POWERCFG_ENABLE; | ||
516 | if (si470x_set_register(radio, POWERCFG) < 0) | ||
517 | return -EIO; | ||
518 | msleep(110); | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | #else | ||
523 | #define si470x_i2c_suspend NULL | ||
524 | #define si470x_i2c_resume NULL | ||
525 | #endif | ||
526 | |||
527 | |||
357 | /* | 528 | /* |
358 | * si470x_i2c_driver - i2c driver interface | 529 | * si470x_i2c_driver - i2c driver interface |
359 | */ | 530 | */ |
@@ -364,6 +535,8 @@ static struct i2c_driver si470x_i2c_driver = { | |||
364 | }, | 535 | }, |
365 | .probe = si470x_i2c_probe, | 536 | .probe = si470x_i2c_probe, |
366 | .remove = __devexit_p(si470x_i2c_remove), | 537 | .remove = __devexit_p(si470x_i2c_remove), |
538 | .suspend = si470x_i2c_suspend, | ||
539 | .resume = si470x_i2c_resume, | ||
367 | .id_table = si470x_i2c_id, | 540 | .id_table = si470x_i2c_id, |
368 | }; | 541 | }; |
369 | 542 | ||
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index f2d0e1ddb301..a96e1b9dd646 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c | |||
@@ -509,89 +509,9 @@ resubmit: | |||
509 | **************************************************************************/ | 509 | **************************************************************************/ |
510 | 510 | ||
511 | /* | 511 | /* |
512 | * si470x_fops_read - read RDS data | ||
513 | */ | ||
514 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
515 | size_t count, loff_t *ppos) | ||
516 | { | ||
517 | struct si470x_device *radio = video_drvdata(file); | ||
518 | int retval = 0; | ||
519 | unsigned int block_count = 0; | ||
520 | |||
521 | /* switch on rds reception */ | ||
522 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
523 | si470x_rds_on(radio); | ||
524 | |||
525 | /* block if no new data available */ | ||
526 | while (radio->wr_index == radio->rd_index) { | ||
527 | if (file->f_flags & O_NONBLOCK) { | ||
528 | retval = -EWOULDBLOCK; | ||
529 | goto done; | ||
530 | } | ||
531 | if (wait_event_interruptible(radio->read_queue, | ||
532 | radio->wr_index != radio->rd_index) < 0) { | ||
533 | retval = -EINTR; | ||
534 | goto done; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | /* calculate block count from byte count */ | ||
539 | count /= 3; | ||
540 | |||
541 | /* copy RDS block out of internal buffer and to user buffer */ | ||
542 | mutex_lock(&radio->lock); | ||
543 | while (block_count < count) { | ||
544 | if (radio->rd_index == radio->wr_index) | ||
545 | break; | ||
546 | |||
547 | /* always transfer rds complete blocks */ | ||
548 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | ||
549 | /* retval = -EFAULT; */ | ||
550 | break; | ||
551 | |||
552 | /* increment and wrap read pointer */ | ||
553 | radio->rd_index += 3; | ||
554 | if (radio->rd_index >= radio->buf_size) | ||
555 | radio->rd_index = 0; | ||
556 | |||
557 | /* increment counters */ | ||
558 | block_count++; | ||
559 | buf += 3; | ||
560 | retval += 3; | ||
561 | } | ||
562 | mutex_unlock(&radio->lock); | ||
563 | |||
564 | done: | ||
565 | return retval; | ||
566 | } | ||
567 | |||
568 | |||
569 | /* | ||
570 | * si470x_fops_poll - poll RDS data | ||
571 | */ | ||
572 | static unsigned int si470x_fops_poll(struct file *file, | ||
573 | struct poll_table_struct *pts) | ||
574 | { | ||
575 | struct si470x_device *radio = video_drvdata(file); | ||
576 | int retval = 0; | ||
577 | |||
578 | /* switch on rds reception */ | ||
579 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
580 | si470x_rds_on(radio); | ||
581 | |||
582 | poll_wait(file, &radio->read_queue, pts); | ||
583 | |||
584 | if (radio->rd_index != radio->wr_index) | ||
585 | retval = POLLIN | POLLRDNORM; | ||
586 | |||
587 | return retval; | ||
588 | } | ||
589 | |||
590 | |||
591 | /* | ||
592 | * si470x_fops_open - file open | 512 | * si470x_fops_open - file open |
593 | */ | 513 | */ |
594 | static int si470x_fops_open(struct file *file) | 514 | int si470x_fops_open(struct file *file) |
595 | { | 515 | { |
596 | struct si470x_device *radio = video_drvdata(file); | 516 | struct si470x_device *radio = video_drvdata(file); |
597 | int retval; | 517 | int retval; |
@@ -645,7 +565,7 @@ done: | |||
645 | /* | 565 | /* |
646 | * si470x_fops_release - file release | 566 | * si470x_fops_release - file release |
647 | */ | 567 | */ |
648 | static int si470x_fops_release(struct file *file) | 568 | int si470x_fops_release(struct file *file) |
649 | { | 569 | { |
650 | struct si470x_device *radio = video_drvdata(file); | 570 | struct si470x_device *radio = video_drvdata(file); |
651 | int retval = 0; | 571 | int retval = 0; |
@@ -688,19 +608,6 @@ done: | |||
688 | } | 608 | } |
689 | 609 | ||
690 | 610 | ||
691 | /* | ||
692 | * si470x_fops - file operations interface | ||
693 | */ | ||
694 | const struct v4l2_file_operations si470x_fops = { | ||
695 | .owner = THIS_MODULE, | ||
696 | .read = si470x_fops_read, | ||
697 | .poll = si470x_fops_poll, | ||
698 | .ioctl = video_ioctl2, | ||
699 | .open = si470x_fops_open, | ||
700 | .release = si470x_fops_release, | ||
701 | }; | ||
702 | |||
703 | |||
704 | 611 | ||
705 | /************************************************************************** | 612 | /************************************************************************** |
706 | * Video4Linux Interface | 613 | * Video4Linux Interface |
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index d0af194d194c..3cd0a29cd6e7 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
33 | #include <linux/smp_lock.h> | 34 | #include <linux/smp_lock.h> |
34 | #include <linux/input.h> | 35 | #include <linux/input.h> |
@@ -181,6 +182,7 @@ struct si470x_device { | |||
181 | 182 | ||
182 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) | 183 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) |
183 | struct i2c_client *client; | 184 | struct i2c_client *client; |
185 | struct work_struct radio_work; | ||
184 | #endif | 186 | #endif |
185 | }; | 187 | }; |
186 | 188 | ||
@@ -212,7 +214,6 @@ struct si470x_device { | |||
212 | /************************************************************************** | 214 | /************************************************************************** |
213 | * Common Functions | 215 | * Common Functions |
214 | **************************************************************************/ | 216 | **************************************************************************/ |
215 | extern const struct v4l2_file_operations si470x_fops; | ||
216 | extern struct video_device si470x_viddev_template; | 217 | extern struct video_device si470x_viddev_template; |
217 | int si470x_get_register(struct si470x_device *radio, int regnr); | 218 | int si470x_get_register(struct si470x_device *radio, int regnr); |
218 | int si470x_set_register(struct si470x_device *radio, int regnr); | 219 | int si470x_set_register(struct si470x_device *radio, int regnr); |
@@ -221,5 +222,7 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq); | |||
221 | int si470x_start(struct si470x_device *radio); | 222 | int si470x_start(struct si470x_device *radio); |
222 | int si470x_stop(struct si470x_device *radio); | 223 | int si470x_stop(struct si470x_device *radio); |
223 | int si470x_rds_on(struct si470x_device *radio); | 224 | int si470x_rds_on(struct si470x_device *radio); |
225 | int si470x_fops_open(struct file *file); | ||
226 | int si470x_fops_release(struct file *file); | ||
224 | int si470x_vidioc_querycap(struct file *file, void *priv, | 227 | int si470x_vidioc_querycap(struct file *file, void *priv, |
225 | struct v4l2_capability *capability); | 228 | struct v4l2_capability *capability); |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9dc74c93bf24..2f83be766d9f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -37,10 +37,6 @@ config VIDEO_BTCX | |||
37 | depends on PCI | 37 | depends on PCI |
38 | tristate | 38 | tristate |
39 | 39 | ||
40 | config VIDEO_IR | ||
41 | tristate | ||
42 | depends on INPUT | ||
43 | |||
44 | config VIDEO_TVEEPROM | 40 | config VIDEO_TVEEPROM |
45 | tristate | 41 | tristate |
46 | depends on I2C | 42 | depends on I2C |
@@ -840,6 +836,12 @@ config SOC_CAMERA_MT9T031 | |||
840 | help | 836 | help |
841 | This driver supports MT9T031 cameras from Micron. | 837 | This driver supports MT9T031 cameras from Micron. |
842 | 838 | ||
839 | config SOC_CAMERA_MT9T112 | ||
840 | tristate "mt9t112 support" | ||
841 | depends on SOC_CAMERA && I2C | ||
842 | help | ||
843 | This driver supports MT9T112 cameras from Aptina. | ||
844 | |||
843 | config SOC_CAMERA_MT9V022 | 845 | config SOC_CAMERA_MT9V022 |
844 | tristate "mt9v022 support" | 846 | tristate "mt9v022 support" |
845 | depends on SOC_CAMERA && I2C | 847 | depends on SOC_CAMERA && I2C |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 7a2dcc34111c..2af68ee84122 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -75,6 +75,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | |||
75 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | 75 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o |
76 | obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o | 76 | obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o |
77 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o | 77 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o |
78 | obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o | ||
78 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o | 79 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o |
79 | obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o | 80 | obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o |
80 | obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o | 81 | obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o |
@@ -149,7 +150,7 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o | |||
149 | obj-$(CONFIG_VIDEO_CX23885) += cx23885/ | 150 | obj-$(CONFIG_VIDEO_CX23885) += cx23885/ |
150 | 151 | ||
151 | obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o | 152 | obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o |
152 | obj-$(CONFIG_SOC_CAMERA) += soc_camera.o | 153 | obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o |
153 | obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o | 154 | obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o |
154 | # soc-camera host drivers have to be linked after camera drivers | 155 | # soc-camera host drivers have to be linked after camera drivers |
155 | obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o | 156 | obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o |
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index d137bac84511..a356d6bd3131 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c | |||
@@ -767,7 +767,6 @@ static struct video_device ar_template = { | |||
767 | .name = "Colour AR VGA", | 767 | .name = "Colour AR VGA", |
768 | .fops = &ar_fops, | 768 | .fops = &ar_fops, |
769 | .release = ar_release, | 769 | .release = ar_release, |
770 | .minor = -1, | ||
771 | }; | 770 | }; |
772 | 771 | ||
773 | #define ALIGN4(x) ((((int)(x)) & 0x3) == 0) | 772 | #define ALIGN4(x) ((((int)(x)) & 0x3) == 0) |
@@ -860,8 +859,8 @@ static int __init ar_init(void) | |||
860 | goto out_dev; | 859 | goto out_dev; |
861 | } | 860 | } |
862 | 861 | ||
863 | printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", | 862 | printk("%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", |
864 | ar->vdev->num, M32R_IRQ_INT3, freq); | 863 | video_device_node_name(ar->vdev), M32R_IRQ_INT3, freq); |
865 | 864 | ||
866 | return 0; | 865 | return 0; |
867 | 866 | ||
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 1485aee18d58..dc67bc40f36f 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include "au0828.h" | 40 | #include "au0828.h" |
41 | #include "au0828-reg.h" | 41 | #include "au0828-reg.h" |
42 | 42 | ||
43 | static LIST_HEAD(au0828_devlist); | ||
44 | static DEFINE_MUTEX(au0828_sysfs_lock); | 43 | static DEFINE_MUTEX(au0828_sysfs_lock); |
45 | 44 | ||
46 | #define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) | 45 | #define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) |
@@ -693,10 +692,8 @@ void au0828_analog_unregister(struct au0828_dev *dev) | |||
693 | dprintk(1, "au0828_release_resources called\n"); | 692 | dprintk(1, "au0828_release_resources called\n"); |
694 | mutex_lock(&au0828_sysfs_lock); | 693 | mutex_lock(&au0828_sysfs_lock); |
695 | 694 | ||
696 | if (dev->vdev) { | 695 | if (dev->vdev) |
697 | list_del(&dev->au0828list); | ||
698 | video_unregister_device(dev->vdev); | 696 | video_unregister_device(dev->vdev); |
699 | } | ||
700 | if (dev->vbi_dev) | 697 | if (dev->vbi_dev) |
701 | video_unregister_device(dev->vbi_dev); | 698 | video_unregister_device(dev->vbi_dev); |
702 | 699 | ||
@@ -737,29 +734,15 @@ static void res_free(struct au0828_fh *fh) | |||
737 | 734 | ||
738 | static int au0828_v4l2_open(struct file *filp) | 735 | static int au0828_v4l2_open(struct file *filp) |
739 | { | 736 | { |
740 | int minor = video_devdata(filp)->minor; | ||
741 | int ret = 0; | 737 | int ret = 0; |
742 | struct au0828_dev *h, *dev = NULL; | 738 | struct au0828_dev *dev = video_drvdata(filp); |
743 | struct au0828_fh *fh; | 739 | struct au0828_fh *fh; |
744 | int type = 0; | 740 | int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
745 | struct list_head *list; | 741 | |
746 | |||
747 | list_for_each(list, &au0828_devlist) { | ||
748 | h = list_entry(list, struct au0828_dev, au0828list); | ||
749 | if (h->vdev->minor == minor) { | ||
750 | dev = h; | ||
751 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
752 | } | ||
753 | #ifdef VBI_IS_WORKING | 742 | #ifdef VBI_IS_WORKING |
754 | if (h->vbi_dev->minor == minor) { | 743 | if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER) |
755 | dev = h; | 744 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
756 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
757 | } | ||
758 | #endif | 745 | #endif |
759 | } | ||
760 | |||
761 | if (NULL == dev) | ||
762 | return -ENODEV; | ||
763 | 746 | ||
764 | fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); | 747 | fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); |
765 | if (NULL == fh) { | 748 | if (NULL == fh) { |
@@ -1587,7 +1570,6 @@ static const struct video_device au0828_video_template = { | |||
1587 | .fops = &au0828_v4l_fops, | 1570 | .fops = &au0828_v4l_fops, |
1588 | .release = video_device_release, | 1571 | .release = video_device_release, |
1589 | .ioctl_ops = &video_ioctl_ops, | 1572 | .ioctl_ops = &video_ioctl_ops, |
1590 | .minor = -1, | ||
1591 | .tvnorms = V4L2_STD_NTSC_M, | 1573 | .tvnorms = V4L2_STD_NTSC_M, |
1592 | .current_norm = V4L2_STD_NTSC_M, | 1574 | .current_norm = V4L2_STD_NTSC_M, |
1593 | }; | 1575 | }; |
@@ -1676,25 +1658,23 @@ int au0828_analog_register(struct au0828_dev *dev, | |||
1676 | strcpy(dev->vbi_dev->name, "au0828a vbi"); | 1658 | strcpy(dev->vbi_dev->name, "au0828a vbi"); |
1677 | #endif | 1659 | #endif |
1678 | 1660 | ||
1679 | list_add_tail(&dev->au0828list, &au0828_devlist); | ||
1680 | |||
1681 | /* Register the v4l2 device */ | 1661 | /* Register the v4l2 device */ |
1662 | video_set_drvdata(dev->vdev, dev); | ||
1682 | retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); | 1663 | retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); |
1683 | if (retval != 0) { | 1664 | if (retval != 0) { |
1684 | dprintk(1, "unable to register video device (error = %d).\n", | 1665 | dprintk(1, "unable to register video device (error = %d).\n", |
1685 | retval); | 1666 | retval); |
1686 | list_del(&dev->au0828list); | ||
1687 | video_device_release(dev->vdev); | 1667 | video_device_release(dev->vdev); |
1688 | return -ENODEV; | 1668 | return -ENODEV; |
1689 | } | 1669 | } |
1690 | 1670 | ||
1691 | #ifdef VBI_IS_WORKING | 1671 | #ifdef VBI_IS_WORKING |
1692 | /* Register the vbi device */ | 1672 | /* Register the vbi device */ |
1673 | video_set_drvdata(dev->vbi_dev, dev); | ||
1693 | retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); | 1674 | retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); |
1694 | if (retval != 0) { | 1675 | if (retval != 0) { |
1695 | dprintk(1, "unable to register vbi device (error = %d).\n", | 1676 | dprintk(1, "unable to register vbi device (error = %d).\n", |
1696 | retval); | 1677 | retval); |
1697 | list_del(&dev->au0828list); | ||
1698 | video_device_release(dev->vbi_dev); | 1678 | video_device_release(dev->vbi_dev); |
1699 | video_device_release(dev->vdev); | 1679 | video_device_release(dev->vdev); |
1700 | return -ENODEV; | 1680 | return -ENODEV; |
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h index b977915efbd0..207f32dec6a6 100644 --- a/drivers/media/video/au0828/au0828.h +++ b/drivers/media/video/au0828/au0828.h | |||
@@ -192,7 +192,6 @@ struct au0828_dev { | |||
192 | struct au0828_dvb dvb; | 192 | struct au0828_dvb dvb; |
193 | 193 | ||
194 | /* Analog */ | 194 | /* Analog */ |
195 | struct list_head au0828list; | ||
196 | struct v4l2_device v4l2_dev; | 195 | struct v4l2_device v4l2_dev; |
197 | int users; | 196 | int users; |
198 | unsigned int stream_on:1; /* Locks streams */ | 197 | unsigned int stream_on:1; /* Locks streams */ |
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a6724019c66f..3182a406bdd1 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c | |||
@@ -3206,24 +3206,24 @@ err: | |||
3206 | 3206 | ||
3207 | static int bttv_open(struct file *file) | 3207 | static int bttv_open(struct file *file) |
3208 | { | 3208 | { |
3209 | int minor = video_devdata(file)->minor; | 3209 | struct video_device *vdev = video_devdata(file); |
3210 | struct bttv *btv = video_drvdata(file); | 3210 | struct bttv *btv = video_drvdata(file); |
3211 | struct bttv_fh *fh; | 3211 | struct bttv_fh *fh; |
3212 | enum v4l2_buf_type type = 0; | 3212 | enum v4l2_buf_type type = 0; |
3213 | 3213 | ||
3214 | dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); | 3214 | dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); |
3215 | 3215 | ||
3216 | lock_kernel(); | 3216 | if (vdev->vfl_type == VFL_TYPE_GRABBER) { |
3217 | if (btv->video_dev->minor == minor) { | ||
3218 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 3217 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
3219 | } else if (btv->vbi_dev->minor == minor) { | 3218 | } else if (vdev->vfl_type == VFL_TYPE_VBI) { |
3220 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 3219 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
3221 | } else { | 3220 | } else { |
3222 | WARN_ON(1); | 3221 | WARN_ON(1); |
3223 | unlock_kernel(); | ||
3224 | return -ENODEV; | 3222 | return -ENODEV; |
3225 | } | 3223 | } |
3226 | 3224 | ||
3225 | lock_kernel(); | ||
3226 | |||
3227 | dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", | 3227 | dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", |
3228 | btv->c.nr,v4l2_type_names[type]); | 3228 | btv->c.nr,v4l2_type_names[type]); |
3229 | 3229 | ||
@@ -3397,7 +3397,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { | |||
3397 | 3397 | ||
3398 | static struct video_device bttv_video_template = { | 3398 | static struct video_device bttv_video_template = { |
3399 | .fops = &bttv_fops, | 3399 | .fops = &bttv_fops, |
3400 | .minor = -1, | ||
3401 | .ioctl_ops = &bttv_ioctl_ops, | 3400 | .ioctl_ops = &bttv_ioctl_ops, |
3402 | .tvnorms = BTTV_NORMS, | 3401 | .tvnorms = BTTV_NORMS, |
3403 | .current_norm = V4L2_STD_PAL, | 3402 | .current_norm = V4L2_STD_PAL, |
@@ -3408,18 +3407,13 @@ static struct video_device bttv_video_template = { | |||
3408 | 3407 | ||
3409 | static int radio_open(struct file *file) | 3408 | static int radio_open(struct file *file) |
3410 | { | 3409 | { |
3411 | int minor = video_devdata(file)->minor; | 3410 | struct video_device *vdev = video_devdata(file); |
3412 | struct bttv *btv = video_drvdata(file); | 3411 | struct bttv *btv = video_drvdata(file); |
3413 | struct bttv_fh *fh; | 3412 | struct bttv_fh *fh; |
3414 | 3413 | ||
3415 | dprintk("bttv: open minor=%d\n",minor); | 3414 | dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); |
3416 | 3415 | ||
3417 | lock_kernel(); | 3416 | lock_kernel(); |
3418 | WARN_ON(btv->radio_dev && btv->radio_dev->minor != minor); | ||
3419 | if (!btv->radio_dev || btv->radio_dev->minor != minor) { | ||
3420 | unlock_kernel(); | ||
3421 | return -ENODEV; | ||
3422 | } | ||
3423 | 3417 | ||
3424 | dprintk("bttv%d: open called (radio)\n",btv->c.nr); | 3418 | dprintk("bttv%d: open called (radio)\n",btv->c.nr); |
3425 | 3419 | ||
@@ -3640,7 +3634,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { | |||
3640 | 3634 | ||
3641 | static struct video_device radio_template = { | 3635 | static struct video_device radio_template = { |
3642 | .fops = &radio_fops, | 3636 | .fops = &radio_fops, |
3643 | .minor = -1, | ||
3644 | .ioctl_ops = &radio_ioctl_ops, | 3637 | .ioctl_ops = &radio_ioctl_ops, |
3645 | }; | 3638 | }; |
3646 | 3639 | ||
@@ -4208,21 +4201,21 @@ static struct video_device *vdev_init(struct bttv *btv, | |||
4208 | static void bttv_unregister_video(struct bttv *btv) | 4201 | static void bttv_unregister_video(struct bttv *btv) |
4209 | { | 4202 | { |
4210 | if (btv->video_dev) { | 4203 | if (btv->video_dev) { |
4211 | if (-1 != btv->video_dev->minor) | 4204 | if (video_is_registered(btv->video_dev)) |
4212 | video_unregister_device(btv->video_dev); | 4205 | video_unregister_device(btv->video_dev); |
4213 | else | 4206 | else |
4214 | video_device_release(btv->video_dev); | 4207 | video_device_release(btv->video_dev); |
4215 | btv->video_dev = NULL; | 4208 | btv->video_dev = NULL; |
4216 | } | 4209 | } |
4217 | if (btv->vbi_dev) { | 4210 | if (btv->vbi_dev) { |
4218 | if (-1 != btv->vbi_dev->minor) | 4211 | if (video_is_registered(btv->vbi_dev)) |
4219 | video_unregister_device(btv->vbi_dev); | 4212 | video_unregister_device(btv->vbi_dev); |
4220 | else | 4213 | else |
4221 | video_device_release(btv->vbi_dev); | 4214 | video_device_release(btv->vbi_dev); |
4222 | btv->vbi_dev = NULL; | 4215 | btv->vbi_dev = NULL; |
4223 | } | 4216 | } |
4224 | if (btv->radio_dev) { | 4217 | if (btv->radio_dev) { |
4225 | if (-1 != btv->radio_dev->minor) | 4218 | if (video_is_registered(btv->radio_dev)) |
4226 | video_unregister_device(btv->radio_dev); | 4219 | video_unregister_device(btv->radio_dev); |
4227 | else | 4220 | else |
4228 | video_device_release(btv->radio_dev); | 4221 | video_device_release(btv->radio_dev); |
@@ -4244,8 +4237,8 @@ static int __devinit bttv_register_video(struct bttv *btv) | |||
4244 | if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, | 4237 | if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, |
4245 | video_nr[btv->c.nr]) < 0) | 4238 | video_nr[btv->c.nr]) < 0) |
4246 | goto err; | 4239 | goto err; |
4247 | printk(KERN_INFO "bttv%d: registered device video%d\n", | 4240 | printk(KERN_INFO "bttv%d: registered device %s\n", |
4248 | btv->c.nr, btv->video_dev->num); | 4241 | btv->c.nr, video_device_node_name(btv->video_dev)); |
4249 | if (device_create_file(&btv->video_dev->dev, | 4242 | if (device_create_file(&btv->video_dev->dev, |
4250 | &dev_attr_card)<0) { | 4243 | &dev_attr_card)<0) { |
4251 | printk(KERN_ERR "bttv%d: device_create_file 'card' " | 4244 | printk(KERN_ERR "bttv%d: device_create_file 'card' " |
@@ -4261,8 +4254,8 @@ static int __devinit bttv_register_video(struct bttv *btv) | |||
4261 | if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, | 4254 | if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, |
4262 | vbi_nr[btv->c.nr]) < 0) | 4255 | vbi_nr[btv->c.nr]) < 0) |
4263 | goto err; | 4256 | goto err; |
4264 | printk(KERN_INFO "bttv%d: registered device vbi%d\n", | 4257 | printk(KERN_INFO "bttv%d: registered device %s\n", |
4265 | btv->c.nr, btv->vbi_dev->num); | 4258 | btv->c.nr, video_device_node_name(btv->vbi_dev)); |
4266 | 4259 | ||
4267 | if (!btv->has_radio) | 4260 | if (!btv->has_radio) |
4268 | return 0; | 4261 | return 0; |
@@ -4273,8 +4266,8 @@ static int __devinit bttv_register_video(struct bttv *btv) | |||
4273 | if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, | 4266 | if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, |
4274 | radio_nr[btv->c.nr]) < 0) | 4267 | radio_nr[btv->c.nr]) < 0) |
4275 | goto err; | 4268 | goto err; |
4276 | printk(KERN_INFO "bttv%d: registered device radio%d\n", | 4269 | printk(KERN_INFO "bttv%d: registered device %s\n", |
4277 | btv->c.nr, btv->radio_dev->num); | 4270 | btv->c.nr, video_device_node_name(btv->radio_dev)); |
4278 | 4271 | ||
4279 | /* all done */ | 4272 | /* all done */ |
4280 | return 0; | 4273 | return 0; |
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index beda363418b0..63aa31a041e8 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c | |||
@@ -40,7 +40,7 @@ static int i2c_debug; | |||
40 | static int i2c_hw; | 40 | static int i2c_hw; |
41 | static int i2c_scan; | 41 | static int i2c_scan; |
42 | module_param(i2c_debug, int, 0644); | 42 | module_param(i2c_debug, int, 0644); |
43 | MODULE_PARM_DESC(i2c_hw,"configure i2c debug level"); | 43 | MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); |
44 | module_param(i2c_hw, int, 0444); | 44 | module_param(i2c_hw, int, 0444); |
45 | MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " | 45 | MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " |
46 | "instead of software bitbang"); | 46 | "instead of software bitbang"); |
@@ -400,7 +400,7 @@ int __devinit init_bttv_i2c(struct bttv *btv) | |||
400 | That's why we probe 0x1a (~0x34) first. CB | 400 | That's why we probe 0x1a (~0x34) first. CB |
401 | */ | 401 | */ |
402 | const unsigned short addr_list[] = { | 402 | const unsigned short addr_list[] = { |
403 | 0x1a, 0x18, 0x4b, 0x64, 0x30, | 403 | 0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71, |
404 | I2C_CLIENT_END | 404 | I2C_CLIENT_END |
405 | }; | 405 | }; |
406 | 406 | ||
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 84a957e52c4b..277a092e1214 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c | |||
@@ -368,7 +368,7 @@ int bttv_input_init(struct bttv *btv) | |||
368 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", | 368 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", |
369 | pci_name(btv->c.pci)); | 369 | pci_name(btv->c.pci)); |
370 | 370 | ||
371 | err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 371 | err = ir_input_init(input_dev, &ir->ir, ir_type); |
372 | if (err < 0) | 372 | if (err < 0) |
373 | goto err_out_free; | 373 | goto err_out_free; |
374 | 374 | ||
@@ -389,7 +389,7 @@ int bttv_input_init(struct bttv *btv) | |||
389 | bttv_ir_start(btv, ir); | 389 | bttv_ir_start(btv, ir); |
390 | 390 | ||
391 | /* all done */ | 391 | /* all done */ |
392 | err = input_register_device(btv->remote->dev); | 392 | err = ir_input_register(btv->remote->dev, ir_codes); |
393 | if (err) | 393 | if (err) |
394 | goto err_out_stop; | 394 | goto err_out_stop; |
395 | 395 | ||
@@ -403,8 +403,6 @@ int bttv_input_init(struct bttv *btv) | |||
403 | bttv_ir_stop(btv); | 403 | bttv_ir_stop(btv); |
404 | btv->remote = NULL; | 404 | btv->remote = NULL; |
405 | err_out_free: | 405 | err_out_free: |
406 | ir_input_free(input_dev); | ||
407 | input_free_device(input_dev); | ||
408 | kfree(ir); | 406 | kfree(ir); |
409 | return err; | 407 | return err; |
410 | } | 408 | } |
@@ -415,8 +413,7 @@ void bttv_input_fini(struct bttv *btv) | |||
415 | return; | 413 | return; |
416 | 414 | ||
417 | bttv_ir_stop(btv); | 415 | bttv_ir_stop(btv); |
418 | ir_input_free(btv->remote->dev); | 416 | ir_input_unregister(btv->remote->dev); |
419 | input_unregister_device(btv->remote->dev); | ||
420 | kfree(btv->remote); | 417 | kfree(btv->remote); |
421 | btv->remote = NULL; | 418 | btv->remote = NULL; |
422 | } | 419 | } |
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 85cf1778827a..e2cbebab959b 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c | |||
@@ -809,8 +809,8 @@ static int init_cqcam(struct parport *port) | |||
809 | return -ENODEV; | 809 | return -ENODEV; |
810 | } | 810 | } |
811 | 811 | ||
812 | printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", | 812 | printk(KERN_INFO "%s: Colour QuickCam found on %s\n", |
813 | qcam->vdev.num, qcam->pport->name); | 813 | video_device_node_name(&qcam->vdev), qcam->pport->name); |
814 | 814 | ||
815 | qcams[num_cams++] = qcam; | 815 | qcams[num_cams++] = qcam; |
816 | 816 | ||
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 10230cb3d210..7bb9c1ec7819 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -1723,7 +1723,6 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { | |||
1723 | 1723 | ||
1724 | static struct video_device cafe_v4l_template = { | 1724 | static struct video_device cafe_v4l_template = { |
1725 | .name = "cafe", | 1725 | .name = "cafe", |
1726 | .minor = -1, /* Get one dynamically */ | ||
1727 | .tvnorms = V4L2_STD_NTSC_M, | 1726 | .tvnorms = V4L2_STD_NTSC_M, |
1728 | .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ | 1727 | .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ |
1729 | 1728 | ||
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 2377313c041a..551ddf216a4b 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/fs.h> | 32 | #include <linux/fs.h> |
33 | #include <linux/vmalloc.h> | 33 | #include <linux/vmalloc.h> |
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/seq_file.h> | ||
35 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
36 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
37 | #include <linux/ctype.h> | 38 | #include <linux/ctype.h> |
@@ -244,72 +245,67 @@ static void rvfree(void *mem, unsigned long size) | |||
244 | #ifdef CONFIG_PROC_FS | 245 | #ifdef CONFIG_PROC_FS |
245 | static struct proc_dir_entry *cpia_proc_root=NULL; | 246 | static struct proc_dir_entry *cpia_proc_root=NULL; |
246 | 247 | ||
247 | static int cpia_read_proc(char *page, char **start, off_t off, | 248 | static int cpia_proc_show(struct seq_file *m, void *v) |
248 | int count, int *eof, void *data) | ||
249 | { | 249 | { |
250 | char *out = page; | 250 | struct cam_data *cam = m->private; |
251 | int len, tmp; | 251 | int tmp; |
252 | struct cam_data *cam = data; | ||
253 | char tmpstr[29]; | 252 | char tmpstr[29]; |
254 | 253 | ||
255 | /* IMPORTANT: This output MUST be kept under PAGE_SIZE | 254 | seq_printf(m, "read-only\n-----------------------\n"); |
256 | * or we need to get more sophisticated. */ | 255 | seq_printf(m, "V4L Driver version: %d.%d.%d\n", |
257 | |||
258 | out += sprintf(out, "read-only\n-----------------------\n"); | ||
259 | out += sprintf(out, "V4L Driver version: %d.%d.%d\n", | ||
260 | CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); | 256 | CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); |
261 | out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n", | 257 | seq_printf(m, "CPIA Version: %d.%02d (%d.%d)\n", |
262 | cam->params.version.firmwareVersion, | 258 | cam->params.version.firmwareVersion, |
263 | cam->params.version.firmwareRevision, | 259 | cam->params.version.firmwareRevision, |
264 | cam->params.version.vcVersion, | 260 | cam->params.version.vcVersion, |
265 | cam->params.version.vcRevision); | 261 | cam->params.version.vcRevision); |
266 | out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n", | 262 | seq_printf(m, "CPIA PnP-ID: %04x:%04x:%04x\n", |
267 | cam->params.pnpID.vendor, cam->params.pnpID.product, | 263 | cam->params.pnpID.vendor, cam->params.pnpID.product, |
268 | cam->params.pnpID.deviceRevision); | 264 | cam->params.pnpID.deviceRevision); |
269 | out += sprintf(out, "VP-Version: %d.%d %04x\n", | 265 | seq_printf(m, "VP-Version: %d.%d %04x\n", |
270 | cam->params.vpVersion.vpVersion, | 266 | cam->params.vpVersion.vpVersion, |
271 | cam->params.vpVersion.vpRevision, | 267 | cam->params.vpVersion.vpRevision, |
272 | cam->params.vpVersion.cameraHeadID); | 268 | cam->params.vpVersion.cameraHeadID); |
273 | 269 | ||
274 | out += sprintf(out, "system_state: %#04x\n", | 270 | seq_printf(m, "system_state: %#04x\n", |
275 | cam->params.status.systemState); | 271 | cam->params.status.systemState); |
276 | out += sprintf(out, "grab_state: %#04x\n", | 272 | seq_printf(m, "grab_state: %#04x\n", |
277 | cam->params.status.grabState); | 273 | cam->params.status.grabState); |
278 | out += sprintf(out, "stream_state: %#04x\n", | 274 | seq_printf(m, "stream_state: %#04x\n", |
279 | cam->params.status.streamState); | 275 | cam->params.status.streamState); |
280 | out += sprintf(out, "fatal_error: %#04x\n", | 276 | seq_printf(m, "fatal_error: %#04x\n", |
281 | cam->params.status.fatalError); | 277 | cam->params.status.fatalError); |
282 | out += sprintf(out, "cmd_error: %#04x\n", | 278 | seq_printf(m, "cmd_error: %#04x\n", |
283 | cam->params.status.cmdError); | 279 | cam->params.status.cmdError); |
284 | out += sprintf(out, "debug_flags: %#04x\n", | 280 | seq_printf(m, "debug_flags: %#04x\n", |
285 | cam->params.status.debugFlags); | 281 | cam->params.status.debugFlags); |
286 | out += sprintf(out, "vp_status: %#04x\n", | 282 | seq_printf(m, "vp_status: %#04x\n", |
287 | cam->params.status.vpStatus); | 283 | cam->params.status.vpStatus); |
288 | out += sprintf(out, "error_code: %#04x\n", | 284 | seq_printf(m, "error_code: %#04x\n", |
289 | cam->params.status.errorCode); | 285 | cam->params.status.errorCode); |
290 | /* QX3 specific entries */ | 286 | /* QX3 specific entries */ |
291 | if (cam->params.qx3.qx3_detected) { | 287 | if (cam->params.qx3.qx3_detected) { |
292 | out += sprintf(out, "button: %4d\n", | 288 | seq_printf(m, "button: %4d\n", |
293 | cam->params.qx3.button); | 289 | cam->params.qx3.button); |
294 | out += sprintf(out, "cradled: %4d\n", | 290 | seq_printf(m, "cradled: %4d\n", |
295 | cam->params.qx3.cradled); | 291 | cam->params.qx3.cradled); |
296 | } | 292 | } |
297 | out += sprintf(out, "video_size: %s\n", | 293 | seq_printf(m, "video_size: %s\n", |
298 | cam->params.format.videoSize == VIDEOSIZE_CIF ? | 294 | cam->params.format.videoSize == VIDEOSIZE_CIF ? |
299 | "CIF " : "QCIF"); | 295 | "CIF " : "QCIF"); |
300 | out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", | 296 | seq_printf(m, "roi: (%3d, %3d) to (%3d, %3d)\n", |
301 | cam->params.roi.colStart*8, | 297 | cam->params.roi.colStart*8, |
302 | cam->params.roi.rowStart*4, | 298 | cam->params.roi.rowStart*4, |
303 | cam->params.roi.colEnd*8, | 299 | cam->params.roi.colEnd*8, |
304 | cam->params.roi.rowEnd*4); | 300 | cam->params.roi.rowEnd*4); |
305 | out += sprintf(out, "actual_fps: %3d\n", cam->fps); | 301 | seq_printf(m, "actual_fps: %3d\n", cam->fps); |
306 | out += sprintf(out, "transfer_rate: %4dkB/s\n", | 302 | seq_printf(m, "transfer_rate: %4dkB/s\n", |
307 | cam->transfer_rate); | 303 | cam->transfer_rate); |
308 | 304 | ||
309 | out += sprintf(out, "\nread-write\n"); | 305 | seq_printf(m, "\nread-write\n"); |
310 | out += sprintf(out, "----------------------- current min" | 306 | seq_printf(m, "----------------------- current min" |
311 | " max default comment\n"); | 307 | " max default comment\n"); |
312 | out += sprintf(out, "brightness: %8d %8d %8d %8d\n", | 308 | seq_printf(m, "brightness: %8d %8d %8d %8d\n", |
313 | cam->params.colourParams.brightness, 0, 100, 50); | 309 | cam->params.colourParams.brightness, 0, 100, 50); |
314 | if (cam->params.version.firmwareVersion == 1 && | 310 | if (cam->params.version.firmwareVersion == 1 && |
315 | cam->params.version.firmwareRevision == 2) | 311 | cam->params.version.firmwareRevision == 2) |
@@ -318,26 +314,26 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
318 | else | 314 | else |
319 | tmp = 96; | 315 | tmp = 96; |
320 | 316 | ||
321 | out += sprintf(out, "contrast: %8d %8d %8d %8d" | 317 | seq_printf(m, "contrast: %8d %8d %8d %8d" |
322 | " steps of 8\n", | 318 | " steps of 8\n", |
323 | cam->params.colourParams.contrast, 0, tmp, 48); | 319 | cam->params.colourParams.contrast, 0, tmp, 48); |
324 | out += sprintf(out, "saturation: %8d %8d %8d %8d\n", | 320 | seq_printf(m, "saturation: %8d %8d %8d %8d\n", |
325 | cam->params.colourParams.saturation, 0, 100, 50); | 321 | cam->params.colourParams.saturation, 0, 100, 50); |
326 | tmp = (25000+5000*cam->params.sensorFps.baserate)/ | 322 | tmp = (25000+5000*cam->params.sensorFps.baserate)/ |
327 | (1<<cam->params.sensorFps.divisor); | 323 | (1<<cam->params.sensorFps.divisor); |
328 | out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n", | 324 | seq_printf(m, "sensor_fps: %4d.%03d %8d %8d %8d\n", |
329 | tmp/1000, tmp%1000, 3, 30, 15); | 325 | tmp/1000, tmp%1000, 3, 30, 15); |
330 | out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n", | 326 | seq_printf(m, "stream_start_line: %8d %8d %8d %8d\n", |
331 | 2*cam->params.streamStartLine, 0, | 327 | 2*cam->params.streamStartLine, 0, |
332 | cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, | 328 | cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, |
333 | cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); | 329 | cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); |
334 | out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n", | 330 | seq_printf(m, "sub_sample: %8s %8s %8s %8s\n", |
335 | cam->params.format.subSample == SUBSAMPLE_420 ? | 331 | cam->params.format.subSample == SUBSAMPLE_420 ? |
336 | "420" : "422", "420", "422", "422"); | 332 | "420" : "422", "420", "422", "422"); |
337 | out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n", | 333 | seq_printf(m, "yuv_order: %8s %8s %8s %8s\n", |
338 | cam->params.format.yuvOrder == YUVORDER_YUYV ? | 334 | cam->params.format.yuvOrder == YUVORDER_YUYV ? |
339 | "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV"); | 335 | "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV"); |
340 | out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", | 336 | seq_printf(m, "ecp_timing: %8s %8s %8s %8s\n", |
341 | cam->params.ecpTiming ? "slow" : "normal", "slow", | 337 | cam->params.ecpTiming ? "slow" : "normal", "slow", |
342 | "normal", "normal"); | 338 | "normal", "normal"); |
343 | 339 | ||
@@ -346,13 +342,13 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
346 | } else { | 342 | } else { |
347 | sprintf(tmpstr, "manual"); | 343 | sprintf(tmpstr, "manual"); |
348 | } | 344 | } |
349 | out += sprintf(out, "color_balance_mode: %8s %8s %8s" | 345 | seq_printf(m, "color_balance_mode: %8s %8s %8s" |
350 | " %8s\n", tmpstr, "manual", "auto", "auto"); | 346 | " %8s\n", tmpstr, "manual", "auto", "auto"); |
351 | out += sprintf(out, "red_gain: %8d %8d %8d %8d\n", | 347 | seq_printf(m, "red_gain: %8d %8d %8d %8d\n", |
352 | cam->params.colourBalance.redGain, 0, 212, 32); | 348 | cam->params.colourBalance.redGain, 0, 212, 32); |
353 | out += sprintf(out, "green_gain: %8d %8d %8d %8d\n", | 349 | seq_printf(m, "green_gain: %8d %8d %8d %8d\n", |
354 | cam->params.colourBalance.greenGain, 0, 212, 6); | 350 | cam->params.colourBalance.greenGain, 0, 212, 6); |
355 | out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n", | 351 | seq_printf(m, "blue_gain: %8d %8d %8d %8d\n", |
356 | cam->params.colourBalance.blueGain, 0, 212, 92); | 352 | cam->params.colourBalance.blueGain, 0, 212, 92); |
357 | 353 | ||
358 | if (cam->params.version.firmwareVersion == 1 && | 354 | if (cam->params.version.firmwareVersion == 1 && |
@@ -363,10 +359,10 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
363 | sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2); | 359 | sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2); |
364 | 360 | ||
365 | if (cam->params.exposure.gainMode == 0) | 361 | if (cam->params.exposure.gainMode == 0) |
366 | out += sprintf(out, "max_gain: unknown %28s" | 362 | seq_printf(m, "max_gain: unknown %28s" |
367 | " powers of 2\n", tmpstr); | 363 | " powers of 2\n", tmpstr); |
368 | else | 364 | else |
369 | out += sprintf(out, "max_gain: %8d %28s" | 365 | seq_printf(m, "max_gain: %8d %28s" |
370 | " 1,2,4 or 8 \n", | 366 | " 1,2,4 or 8 \n", |
371 | 1<<(cam->params.exposure.gainMode-1), tmpstr); | 367 | 1<<(cam->params.exposure.gainMode-1), tmpstr); |
372 | 368 | ||
@@ -382,12 +378,12 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
382 | sprintf(tmpstr, "unknown"); | 378 | sprintf(tmpstr, "unknown"); |
383 | break; | 379 | break; |
384 | } | 380 | } |
385 | out += sprintf(out, "exposure_mode: %8s %8s %8s" | 381 | seq_printf(m, "exposure_mode: %8s %8s %8s" |
386 | " %8s\n", tmpstr, "manual", "auto", "auto"); | 382 | " %8s\n", tmpstr, "manual", "auto", "auto"); |
387 | out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n", | 383 | seq_printf(m, "centre_weight: %8s %8s %8s %8s\n", |
388 | (2-cam->params.exposure.centreWeight) ? "on" : "off", | 384 | (2-cam->params.exposure.centreWeight) ? "on" : "off", |
389 | "off", "on", "on"); | 385 | "off", "on", "on"); |
390 | out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", | 386 | seq_printf(m, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", |
391 | 1<<cam->params.exposure.gain, 1, 1); | 387 | 1<<cam->params.exposure.gain, 1, 1); |
392 | if (cam->params.version.firmwareVersion == 1 && | 388 | if (cam->params.version.firmwareVersion == 1 && |
393 | cam->params.version.firmwareRevision == 2) | 389 | cam->params.version.firmwareRevision == 2) |
@@ -396,7 +392,7 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
396 | else | 392 | else |
397 | tmp = 510; | 393 | tmp = 510; |
398 | 394 | ||
399 | out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", | 395 | seq_printf(m, "fine_exp: %8d %8d %8d %8d\n", |
400 | cam->params.exposure.fineExp*2, 0, tmp, 0); | 396 | cam->params.exposure.fineExp*2, 0, tmp, 0); |
401 | if (cam->params.version.firmwareVersion == 1 && | 397 | if (cam->params.version.firmwareVersion == 1 && |
402 | cam->params.version.firmwareRevision == 2) | 398 | cam->params.version.firmwareRevision == 2) |
@@ -405,127 +401,122 @@ static int cpia_read_proc(char *page, char **start, off_t off, | |||
405 | else | 401 | else |
406 | tmp = MAX_EXP; | 402 | tmp = MAX_EXP; |
407 | 403 | ||
408 | out += sprintf(out, "coarse_exp: %8d %8d %8d" | 404 | seq_printf(m, "coarse_exp: %8d %8d %8d" |
409 | " %8d\n", cam->params.exposure.coarseExpLo+ | 405 | " %8d\n", cam->params.exposure.coarseExpLo+ |
410 | 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); | 406 | 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); |
411 | out += sprintf(out, "red_comp: %8d %8d %8d %8d\n", | 407 | seq_printf(m, "red_comp: %8d %8d %8d %8d\n", |
412 | cam->params.exposure.redComp, COMP_RED, 255, COMP_RED); | 408 | cam->params.exposure.redComp, COMP_RED, 255, COMP_RED); |
413 | out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n", | 409 | seq_printf(m, "green1_comp: %8d %8d %8d %8d\n", |
414 | cam->params.exposure.green1Comp, COMP_GREEN1, 255, | 410 | cam->params.exposure.green1Comp, COMP_GREEN1, 255, |
415 | COMP_GREEN1); | 411 | COMP_GREEN1); |
416 | out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n", | 412 | seq_printf(m, "green2_comp: %8d %8d %8d %8d\n", |
417 | cam->params.exposure.green2Comp, COMP_GREEN2, 255, | 413 | cam->params.exposure.green2Comp, COMP_GREEN2, 255, |
418 | COMP_GREEN2); | 414 | COMP_GREEN2); |
419 | out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n", | 415 | seq_printf(m, "blue_comp: %8d %8d %8d %8d\n", |
420 | cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE); | 416 | cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE); |
421 | 417 | ||
422 | out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n", | 418 | seq_printf(m, "apcor_gain1: %#8x %#8x %#8x %#8x\n", |
423 | cam->params.apcor.gain1, 0, 0xff, 0x1c); | 419 | cam->params.apcor.gain1, 0, 0xff, 0x1c); |
424 | out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n", | 420 | seq_printf(m, "apcor_gain2: %#8x %#8x %#8x %#8x\n", |
425 | cam->params.apcor.gain2, 0, 0xff, 0x1a); | 421 | cam->params.apcor.gain2, 0, 0xff, 0x1a); |
426 | out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n", | 422 | seq_printf(m, "apcor_gain4: %#8x %#8x %#8x %#8x\n", |
427 | cam->params.apcor.gain4, 0, 0xff, 0x2d); | 423 | cam->params.apcor.gain4, 0, 0xff, 0x2d); |
428 | out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n", | 424 | seq_printf(m, "apcor_gain8: %#8x %#8x %#8x %#8x\n", |
429 | cam->params.apcor.gain8, 0, 0xff, 0x2a); | 425 | cam->params.apcor.gain8, 0, 0xff, 0x2a); |
430 | out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n", | 426 | seq_printf(m, "vl_offset_gain1: %8d %8d %8d %8d\n", |
431 | cam->params.vlOffset.gain1, 0, 255, 24); | 427 | cam->params.vlOffset.gain1, 0, 255, 24); |
432 | out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n", | 428 | seq_printf(m, "vl_offset_gain2: %8d %8d %8d %8d\n", |
433 | cam->params.vlOffset.gain2, 0, 255, 28); | 429 | cam->params.vlOffset.gain2, 0, 255, 28); |
434 | out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n", | 430 | seq_printf(m, "vl_offset_gain4: %8d %8d %8d %8d\n", |
435 | cam->params.vlOffset.gain4, 0, 255, 30); | 431 | cam->params.vlOffset.gain4, 0, 255, 30); |
436 | out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n", | 432 | seq_printf(m, "vl_offset_gain8: %8d %8d %8d %8d\n", |
437 | cam->params.vlOffset.gain8, 0, 255, 30); | 433 | cam->params.vlOffset.gain8, 0, 255, 30); |
438 | out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n", | 434 | seq_printf(m, "flicker_control: %8s %8s %8s %8s\n", |
439 | cam->params.flickerControl.flickerMode ? "on" : "off", | 435 | cam->params.flickerControl.flickerMode ? "on" : "off", |
440 | "off", "on", "off"); | 436 | "off", "on", "off"); |
441 | out += sprintf(out, "mains_frequency: %8d %8d %8d %8d" | 437 | seq_printf(m, "mains_frequency: %8d %8d %8d %8d" |
442 | " only 50/60\n", | 438 | " only 50/60\n", |
443 | cam->mainsFreq ? 60 : 50, 50, 60, 50); | 439 | cam->mainsFreq ? 60 : 50, 50, 60, 50); |
444 | if(cam->params.flickerControl.allowableOverExposure < 0) | 440 | if(cam->params.flickerControl.allowableOverExposure < 0) |
445 | out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n", | 441 | seq_printf(m, "allowable_overexposure: %4dauto auto %8d auto\n", |
446 | -cam->params.flickerControl.allowableOverExposure, | 442 | -cam->params.flickerControl.allowableOverExposure, |
447 | 255); | 443 | 255); |
448 | else | 444 | else |
449 | out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n", | 445 | seq_printf(m, "allowable_overexposure: %8d auto %8d auto\n", |
450 | cam->params.flickerControl.allowableOverExposure, | 446 | cam->params.flickerControl.allowableOverExposure, |
451 | 255); | 447 | 255); |
452 | out += sprintf(out, "compression_mode: "); | 448 | seq_printf(m, "compression_mode: "); |
453 | switch(cam->params.compression.mode) { | 449 | switch(cam->params.compression.mode) { |
454 | case CPIA_COMPRESSION_NONE: | 450 | case CPIA_COMPRESSION_NONE: |
455 | out += sprintf(out, "%8s", "none"); | 451 | seq_printf(m, "%8s", "none"); |
456 | break; | 452 | break; |
457 | case CPIA_COMPRESSION_AUTO: | 453 | case CPIA_COMPRESSION_AUTO: |
458 | out += sprintf(out, "%8s", "auto"); | 454 | seq_printf(m, "%8s", "auto"); |
459 | break; | 455 | break; |
460 | case CPIA_COMPRESSION_MANUAL: | 456 | case CPIA_COMPRESSION_MANUAL: |
461 | out += sprintf(out, "%8s", "manual"); | 457 | seq_printf(m, "%8s", "manual"); |
462 | break; | 458 | break; |
463 | default: | 459 | default: |
464 | out += sprintf(out, "%8s", "unknown"); | 460 | seq_printf(m, "%8s", "unknown"); |
465 | break; | 461 | break; |
466 | } | 462 | } |
467 | out += sprintf(out, " none,auto,manual auto\n"); | 463 | seq_printf(m, " none,auto,manual auto\n"); |
468 | out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", | 464 | seq_printf(m, "decimation_enable: %8s %8s %8s %8s\n", |
469 | cam->params.compression.decimation == | 465 | cam->params.compression.decimation == |
470 | DECIMATION_ENAB ? "on":"off", "off", "on", | 466 | DECIMATION_ENAB ? "on":"off", "off", "on", |
471 | "off"); | 467 | "off"); |
472 | out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", | 468 | seq_printf(m, "compression_target: %9s %9s %9s %9s\n", |
473 | cam->params.compressionTarget.frTargeting == | 469 | cam->params.compressionTarget.frTargeting == |
474 | CPIA_COMPRESSION_TARGET_FRAMERATE ? | 470 | CPIA_COMPRESSION_TARGET_FRAMERATE ? |
475 | "framerate":"quality", | 471 | "framerate":"quality", |
476 | "framerate", "quality", "quality"); | 472 | "framerate", "quality", "quality"); |
477 | out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", | 473 | seq_printf(m, "target_framerate: %8d %8d %8d %8d\n", |
478 | cam->params.compressionTarget.targetFR, 1, 30, 15); | 474 | cam->params.compressionTarget.targetFR, 1, 30, 15); |
479 | out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", | 475 | seq_printf(m, "target_quality: %8d %8d %8d %8d\n", |
480 | cam->params.compressionTarget.targetQ, 1, 64, 5); | 476 | cam->params.compressionTarget.targetQ, 1, 64, 5); |
481 | out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", | 477 | seq_printf(m, "y_threshold: %8d %8d %8d %8d\n", |
482 | cam->params.yuvThreshold.yThreshold, 0, 31, 6); | 478 | cam->params.yuvThreshold.yThreshold, 0, 31, 6); |
483 | out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", | 479 | seq_printf(m, "uv_threshold: %8d %8d %8d %8d\n", |
484 | cam->params.yuvThreshold.uvThreshold, 0, 31, 6); | 480 | cam->params.yuvThreshold.uvThreshold, 0, 31, 6); |
485 | out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", | 481 | seq_printf(m, "hysteresis: %8d %8d %8d %8d\n", |
486 | cam->params.compressionParams.hysteresis, 0, 255, 3); | 482 | cam->params.compressionParams.hysteresis, 0, 255, 3); |
487 | out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", | 483 | seq_printf(m, "threshold_max: %8d %8d %8d %8d\n", |
488 | cam->params.compressionParams.threshMax, 0, 255, 11); | 484 | cam->params.compressionParams.threshMax, 0, 255, 11); |
489 | out += sprintf(out, "small_step: %8d %8d %8d %8d\n", | 485 | seq_printf(m, "small_step: %8d %8d %8d %8d\n", |
490 | cam->params.compressionParams.smallStep, 0, 255, 1); | 486 | cam->params.compressionParams.smallStep, 0, 255, 1); |
491 | out += sprintf(out, "large_step: %8d %8d %8d %8d\n", | 487 | seq_printf(m, "large_step: %8d %8d %8d %8d\n", |
492 | cam->params.compressionParams.largeStep, 0, 255, 3); | 488 | cam->params.compressionParams.largeStep, 0, 255, 3); |
493 | out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n", | 489 | seq_printf(m, "decimation_hysteresis: %8d %8d %8d %8d\n", |
494 | cam->params.compressionParams.decimationHysteresis, | 490 | cam->params.compressionParams.decimationHysteresis, |
495 | 0, 255, 2); | 491 | 0, 255, 2); |
496 | out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n", | 492 | seq_printf(m, "fr_diff_step_thresh: %8d %8d %8d %8d\n", |
497 | cam->params.compressionParams.frDiffStepThresh, | 493 | cam->params.compressionParams.frDiffStepThresh, |
498 | 0, 255, 5); | 494 | 0, 255, 5); |
499 | out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n", | 495 | seq_printf(m, "q_diff_step_thresh: %8d %8d %8d %8d\n", |
500 | cam->params.compressionParams.qDiffStepThresh, | 496 | cam->params.compressionParams.qDiffStepThresh, |
501 | 0, 255, 3); | 497 | 0, 255, 3); |
502 | out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", | 498 | seq_printf(m, "decimation_thresh_mod: %8d %8d %8d %8d\n", |
503 | cam->params.compressionParams.decimationThreshMod, | 499 | cam->params.compressionParams.decimationThreshMod, |
504 | 0, 255, 2); | 500 | 0, 255, 2); |
505 | /* QX3 specific entries */ | 501 | /* QX3 specific entries */ |
506 | if (cam->params.qx3.qx3_detected) { | 502 | if (cam->params.qx3.qx3_detected) { |
507 | out += sprintf(out, "toplight: %8s %8s %8s %8s\n", | 503 | seq_printf(m, "toplight: %8s %8s %8s %8s\n", |
508 | cam->params.qx3.toplight ? "on" : "off", | 504 | cam->params.qx3.toplight ? "on" : "off", |
509 | "off", "on", "off"); | 505 | "off", "on", "off"); |
510 | out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n", | 506 | seq_printf(m, "bottomlight: %8s %8s %8s %8s\n", |
511 | cam->params.qx3.bottomlight ? "on" : "off", | 507 | cam->params.qx3.bottomlight ? "on" : "off", |
512 | "off", "on", "off"); | 508 | "off", "on", "off"); |
513 | } | 509 | } |
514 | 510 | ||
515 | len = out - page; | 511 | return 0; |
516 | len -= off; | ||
517 | if (len < count) { | ||
518 | *eof = 1; | ||
519 | if (len <= 0) return 0; | ||
520 | } else | ||
521 | len = count; | ||
522 | |||
523 | *start = page + off; | ||
524 | return len; | ||
525 | } | 512 | } |
526 | 513 | ||
514 | static int cpia_proc_open(struct inode *inode, struct file *file) | ||
515 | { | ||
516 | return single_open(file, cpia_proc_show, PDE(inode)->data); | ||
517 | } | ||
527 | 518 | ||
528 | static int match(char *checkstr, char **buffer, unsigned long *count, | 519 | static int match(char *checkstr, char **buffer, size_t *count, |
529 | int *find_colon, int *err) | 520 | int *find_colon, int *err) |
530 | { | 521 | { |
531 | int ret, colon_found = 1; | 522 | int ret, colon_found = 1; |
@@ -551,7 +542,7 @@ static int match(char *checkstr, char **buffer, unsigned long *count, | |||
551 | return ret; | 542 | return ret; |
552 | } | 543 | } |
553 | 544 | ||
554 | static unsigned long int value(char **buffer, unsigned long *count, int *err) | 545 | static unsigned long int value(char **buffer, size_t *count, int *err) |
555 | { | 546 | { |
556 | char *p; | 547 | char *p; |
557 | unsigned long int ret; | 548 | unsigned long int ret; |
@@ -565,10 +556,10 @@ static unsigned long int value(char **buffer, unsigned long *count, int *err) | |||
565 | return ret; | 556 | return ret; |
566 | } | 557 | } |
567 | 558 | ||
568 | static int cpia_write_proc(struct file *file, const char __user *buf, | 559 | static ssize_t cpia_proc_write(struct file *file, const char __user *buf, |
569 | unsigned long count, void *data) | 560 | size_t count, loff_t *pos) |
570 | { | 561 | { |
571 | struct cam_data *cam = data; | 562 | struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data; |
572 | struct cam_params new_params; | 563 | struct cam_params new_params; |
573 | char *page, *buffer; | 564 | char *page, *buffer; |
574 | int retval, find_colon; | 565 | int retval, find_colon; |
@@ -582,7 +573,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf, | |||
582 | * from the comx driver | 573 | * from the comx driver |
583 | */ | 574 | */ |
584 | if (count > PAGE_SIZE) { | 575 | if (count > PAGE_SIZE) { |
585 | printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE); | 576 | printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE); |
586 | return -ENOSPC; | 577 | return -ENOSPC; |
587 | } | 578 | } |
588 | 579 | ||
@@ -1340,23 +1331,28 @@ out: | |||
1340 | return retval; | 1331 | return retval; |
1341 | } | 1332 | } |
1342 | 1333 | ||
1334 | static const struct file_operations cpia_proc_fops = { | ||
1335 | .owner = THIS_MODULE, | ||
1336 | .open = cpia_proc_open, | ||
1337 | .read = seq_read, | ||
1338 | .llseek = seq_lseek, | ||
1339 | .release = single_release, | ||
1340 | .write = cpia_proc_write, | ||
1341 | }; | ||
1342 | |||
1343 | static void create_proc_cpia_cam(struct cam_data *cam) | 1343 | static void create_proc_cpia_cam(struct cam_data *cam) |
1344 | { | 1344 | { |
1345 | char name[5 + 1 + 10 + 1]; | ||
1346 | struct proc_dir_entry *ent; | 1345 | struct proc_dir_entry *ent; |
1347 | 1346 | ||
1348 | if (!cpia_proc_root || !cam) | 1347 | if (!cpia_proc_root || !cam) |
1349 | return; | 1348 | return; |
1350 | 1349 | ||
1351 | snprintf(name, sizeof(name), "video%d", cam->vdev.num); | 1350 | ent = proc_create_data(video_device_node_name(&cam->vdev), |
1352 | 1351 | S_IRUGO|S_IWUSR, cpia_proc_root, | |
1353 | ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); | 1352 | &cpia_proc_fops, cam); |
1354 | if (!ent) | 1353 | if (!ent) |
1355 | return; | 1354 | return; |
1356 | 1355 | ||
1357 | ent->data = cam; | ||
1358 | ent->read_proc = cpia_read_proc; | ||
1359 | ent->write_proc = cpia_write_proc; | ||
1360 | /* | 1356 | /* |
1361 | size of the proc entry is 3736 bytes for the standard webcam; | 1357 | size of the proc entry is 3736 bytes for the standard webcam; |
1362 | the extra features of the QX3 microscope add 189 bytes. | 1358 | the extra features of the QX3 microscope add 189 bytes. |
@@ -1368,13 +1364,10 @@ static void create_proc_cpia_cam(struct cam_data *cam) | |||
1368 | 1364 | ||
1369 | static void destroy_proc_cpia_cam(struct cam_data *cam) | 1365 | static void destroy_proc_cpia_cam(struct cam_data *cam) |
1370 | { | 1366 | { |
1371 | char name[5 + 1 + 10 + 1]; | ||
1372 | |||
1373 | if (!cam || !cam->proc_entry) | 1367 | if (!cam || !cam->proc_entry) |
1374 | return; | 1368 | return; |
1375 | 1369 | ||
1376 | snprintf(name, sizeof(name), "video%d", cam->vdev.num); | 1370 | remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root); |
1377 | remove_proc_entry(name, cpia_proc_root); | ||
1378 | cam->proc_entry = NULL; | 1371 | cam->proc_entry = NULL; |
1379 | } | 1372 | } |
1380 | 1373 | ||
@@ -3999,7 +3992,7 @@ void cpia_unregister_camera(struct cam_data *cam) | |||
3999 | } | 3992 | } |
4000 | 3993 | ||
4001 | #ifdef CONFIG_PROC_FS | 3994 | #ifdef CONFIG_PROC_FS |
4002 | DBG("destroying /proc/cpia/video%d\n", cam->vdev.num); | 3995 | DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev)); |
4003 | destroy_proc_cpia_cam(cam); | 3996 | destroy_proc_cpia_cam(cam); |
4004 | #endif | 3997 | #endif |
4005 | if (!cam->open_count) { | 3998 | if (!cam->open_count) { |
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 0b4a8f309cfa..6f91415eb7b4 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c | |||
@@ -38,17 +38,12 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/videodev.h> | 40 | #include <linux/videodev.h> |
41 | #include <linux/stringify.h> | ||
41 | #include <media/v4l2-ioctl.h> | 42 | #include <media/v4l2-ioctl.h> |
42 | 43 | ||
43 | #include "cpia2.h" | 44 | #include "cpia2.h" |
44 | #include "cpia2dev.h" | 45 | #include "cpia2dev.h" |
45 | 46 | ||
46 | |||
47 | //#define _CPIA2_DEBUG_ | ||
48 | |||
49 | #define MAKE_STRING_1(x) #x | ||
50 | #define MAKE_STRING(x) MAKE_STRING_1(x) | ||
51 | |||
52 | static int video_nr = -1; | 47 | static int video_nr = -1; |
53 | module_param(video_nr, int, 0); | 48 | module_param(video_nr, int, 0); |
54 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); | 49 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); |
@@ -60,26 +55,26 @@ MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k) | |||
60 | static int num_buffers = 3; | 55 | static int num_buffers = 3; |
61 | module_param(num_buffers, int, 0); | 56 | module_param(num_buffers, int, 0); |
62 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" | 57 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" |
63 | MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); | 58 | __stringify(VIDEO_MAX_FRAME) ", default 3)"); |
64 | 59 | ||
65 | static int alternate = DEFAULT_ALT; | 60 | static int alternate = DEFAULT_ALT; |
66 | module_param(alternate, int, 0); | 61 | module_param(alternate, int, 0); |
67 | MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" | 62 | MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" |
68 | MAKE_STRING(USBIF_ISO_6) ", default " | 63 | __stringify(USBIF_ISO_6) ", default " |
69 | MAKE_STRING(DEFAULT_ALT) ")"); | 64 | __stringify(DEFAULT_ALT) ")"); |
70 | 65 | ||
71 | static int flicker_freq = 60; | 66 | static int flicker_freq = 60; |
72 | module_param(flicker_freq, int, 0); | 67 | module_param(flicker_freq, int, 0); |
73 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" | 68 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or" |
74 | MAKE_STRING(60) ", default " | 69 | __stringify(60) ", default " |
75 | MAKE_STRING(60) ")"); | 70 | __stringify(60) ")"); |
76 | 71 | ||
77 | static int flicker_mode = NEVER_FLICKER; | 72 | static int flicker_mode = NEVER_FLICKER; |
78 | module_param(flicker_mode, int, 0); | 73 | module_param(flicker_mode, int, 0); |
79 | MODULE_PARM_DESC(flicker_mode, | 74 | MODULE_PARM_DESC(flicker_mode, |
80 | "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" | 75 | "Flicker supression (" __stringify(NEVER_FLICKER) "or" |
81 | MAKE_STRING(ANTI_FLICKER_ON) ", default " | 76 | __stringify(ANTI_FLICKER_ON) ", default " |
82 | MAKE_STRING(NEVER_FLICKER) ")"); | 77 | __stringify(NEVER_FLICKER) ")"); |
83 | 78 | ||
84 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); | 79 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); |
85 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); | 80 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); |
@@ -1926,7 +1921,6 @@ static const struct v4l2_file_operations fops_template = { | |||
1926 | static struct video_device cpia2_template = { | 1921 | static struct video_device cpia2_template = { |
1927 | /* I could not find any place for the old .initialize initializer?? */ | 1922 | /* I could not find any place for the old .initialize initializer?? */ |
1928 | .name= "CPiA2 Camera", | 1923 | .name= "CPiA2 Camera", |
1929 | .minor= -1, | ||
1930 | .fops= &fops_template, | 1924 | .fops= &fops_template, |
1931 | .release= video_device_release, | 1925 | .release= video_device_release, |
1932 | }; | 1926 | }; |
@@ -1967,9 +1961,9 @@ void cpia2_unregister_camera(struct camera_data *cam) | |||
1967 | if (!cam->open_count) { | 1961 | if (!cam->open_count) { |
1968 | video_unregister_device(cam->vdev); | 1962 | video_unregister_device(cam->vdev); |
1969 | } else { | 1963 | } else { |
1970 | LOG("/dev/video%d removed while open, " | 1964 | LOG("%s removed while open, deferring " |
1971 | "deferring video_unregister_device\n", | 1965 | "video_unregister_device\n", |
1972 | cam->vdev->num); | 1966 | video_device_node_name(cam->vdev)); |
1973 | } | 1967 | } |
1974 | } | 1968 | } |
1975 | 1969 | ||
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 4e278db31cc9..c0885c69fd89 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -758,8 +758,8 @@ int cx18_v4l2_open(struct file *filp) | |||
758 | 758 | ||
759 | mutex_lock(&cx->serialize_lock); | 759 | mutex_lock(&cx->serialize_lock); |
760 | if (cx18_init_on_first_open(cx)) { | 760 | if (cx18_init_on_first_open(cx)) { |
761 | CX18_ERR("Failed to initialize on minor %d\n", | 761 | CX18_ERR("Failed to initialize on %s\n", |
762 | video_dev->minor); | 762 | video_device_node_name(video_dev)); |
763 | mutex_unlock(&cx->serialize_lock); | 763 | mutex_unlock(&cx->serialize_lock); |
764 | return -ENXIO; | 764 | return -ENXIO; |
765 | } | 765 | } |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c398651dd74c..987a9308d938 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -219,6 +219,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) | |||
219 | { | 219 | { |
220 | struct cx18_stream *s = &cx->streams[type]; | 220 | struct cx18_stream *s = &cx->streams[type]; |
221 | int vfl_type = cx18_stream_info[type].vfl_type; | 221 | int vfl_type = cx18_stream_info[type].vfl_type; |
222 | const char *name; | ||
222 | int num, ret; | 223 | int num, ret; |
223 | 224 | ||
224 | /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? | 225 | /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? |
@@ -258,31 +259,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type) | |||
258 | s->video_dev = NULL; | 259 | s->video_dev = NULL; |
259 | return ret; | 260 | return ret; |
260 | } | 261 | } |
261 | num = s->video_dev->num; | 262 | |
263 | name = video_device_node_name(s->video_dev); | ||
262 | 264 | ||
263 | switch (vfl_type) { | 265 | switch (vfl_type) { |
264 | case VFL_TYPE_GRABBER: | 266 | case VFL_TYPE_GRABBER: |
265 | CX18_INFO("Registered device video%d for %s " | 267 | CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", |
266 | "(%d x %d.%02d kB)\n", | 268 | name, s->name, cx->stream_buffers[type], |
267 | num, s->name, cx->stream_buffers[type], | ||
268 | cx->stream_buf_size[type] / 1024, | 269 | cx->stream_buf_size[type] / 1024, |
269 | (cx->stream_buf_size[type] * 100 / 1024) % 100); | 270 | (cx->stream_buf_size[type] * 100 / 1024) % 100); |
270 | break; | 271 | break; |
271 | 272 | ||
272 | case VFL_TYPE_RADIO: | 273 | case VFL_TYPE_RADIO: |
273 | CX18_INFO("Registered device radio%d for %s\n", | 274 | CX18_INFO("Registered device %s for %s\n", name, s->name); |
274 | num, s->name); | ||
275 | break; | 275 | break; |
276 | 276 | ||
277 | case VFL_TYPE_VBI: | 277 | case VFL_TYPE_VBI: |
278 | if (cx->stream_buffers[type]) | 278 | if (cx->stream_buffers[type]) |
279 | CX18_INFO("Registered device vbi%d for %s " | 279 | CX18_INFO("Registered device %s for %s " |
280 | "(%d x %d bytes)\n", | 280 | "(%d x %d bytes)\n", |
281 | num, s->name, cx->stream_buffers[type], | 281 | name, s->name, cx->stream_buffers[type], |
282 | cx->stream_buf_size[type]); | 282 | cx->stream_buf_size[type]); |
283 | else | 283 | else |
284 | CX18_INFO("Registered device vbi%d for %s\n", | 284 | CX18_INFO("Registered device %s for %s\n", |
285 | num, s->name); | 285 | name, s->name); |
286 | break; | 286 | break; |
287 | } | 287 | } |
288 | 288 | ||
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 319c459459e0..a54908235009 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c | |||
@@ -68,19 +68,19 @@ struct cx231xx_board cx231xx_boards[] = { | |||
68 | .type = CX231XX_VMUX_TELEVISION, | 68 | .type = CX231XX_VMUX_TELEVISION, |
69 | .vmux = CX231XX_VIN_3_1, | 69 | .vmux = CX231XX_VIN_3_1, |
70 | .amux = CX231XX_AMUX_VIDEO, | 70 | .amux = CX231XX_AMUX_VIDEO, |
71 | .gpio = 0, | 71 | .gpio = NULL, |
72 | }, { | 72 | }, { |
73 | .type = CX231XX_VMUX_COMPOSITE1, | 73 | .type = CX231XX_VMUX_COMPOSITE1, |
74 | .vmux = CX231XX_VIN_2_1, | 74 | .vmux = CX231XX_VIN_2_1, |
75 | .amux = CX231XX_AMUX_LINE_IN, | 75 | .amux = CX231XX_AMUX_LINE_IN, |
76 | .gpio = 0, | 76 | .gpio = NULL, |
77 | }, { | 77 | }, { |
78 | .type = CX231XX_VMUX_SVIDEO, | 78 | .type = CX231XX_VMUX_SVIDEO, |
79 | .vmux = CX231XX_VIN_1_1 | | 79 | .vmux = CX231XX_VIN_1_1 | |
80 | (CX231XX_VIN_1_2 << 8) | | 80 | (CX231XX_VIN_1_2 << 8) | |
81 | CX25840_SVIDEO_ON, | 81 | CX25840_SVIDEO_ON, |
82 | .amux = CX231XX_AMUX_LINE_IN, | 82 | .amux = CX231XX_AMUX_LINE_IN, |
83 | .gpio = 0, | 83 | .gpio = NULL, |
84 | } | 84 | } |
85 | }, | 85 | }, |
86 | }, | 86 | }, |
@@ -107,19 +107,19 @@ struct cx231xx_board cx231xx_boards[] = { | |||
107 | .type = CX231XX_VMUX_TELEVISION, | 107 | .type = CX231XX_VMUX_TELEVISION, |
108 | .vmux = CX231XX_VIN_3_1, | 108 | .vmux = CX231XX_VIN_3_1, |
109 | .amux = CX231XX_AMUX_VIDEO, | 109 | .amux = CX231XX_AMUX_VIDEO, |
110 | .gpio = 0, | 110 | .gpio = NULL, |
111 | }, { | 111 | }, { |
112 | .type = CX231XX_VMUX_COMPOSITE1, | 112 | .type = CX231XX_VMUX_COMPOSITE1, |
113 | .vmux = CX231XX_VIN_2_1, | 113 | .vmux = CX231XX_VIN_2_1, |
114 | .amux = CX231XX_AMUX_LINE_IN, | 114 | .amux = CX231XX_AMUX_LINE_IN, |
115 | .gpio = 0, | 115 | .gpio = NULL, |
116 | }, { | 116 | }, { |
117 | .type = CX231XX_VMUX_SVIDEO, | 117 | .type = CX231XX_VMUX_SVIDEO, |
118 | .vmux = CX231XX_VIN_1_1 | | 118 | .vmux = CX231XX_VIN_1_1 | |
119 | (CX231XX_VIN_1_2 << 8) | | 119 | (CX231XX_VIN_1_2 << 8) | |
120 | CX25840_SVIDEO_ON, | 120 | CX25840_SVIDEO_ON, |
121 | .amux = CX231XX_AMUX_LINE_IN, | 121 | .amux = CX231XX_AMUX_LINE_IN, |
122 | .gpio = 0, | 122 | .gpio = NULL, |
123 | } | 123 | } |
124 | }, | 124 | }, |
125 | }, | 125 | }, |
@@ -147,19 +147,19 @@ struct cx231xx_board cx231xx_boards[] = { | |||
147 | .type = CX231XX_VMUX_TELEVISION, | 147 | .type = CX231XX_VMUX_TELEVISION, |
148 | .vmux = CX231XX_VIN_3_1, | 148 | .vmux = CX231XX_VIN_3_1, |
149 | .amux = CX231XX_AMUX_VIDEO, | 149 | .amux = CX231XX_AMUX_VIDEO, |
150 | .gpio = 0, | 150 | .gpio = NULL, |
151 | }, { | 151 | }, { |
152 | .type = CX231XX_VMUX_COMPOSITE1, | 152 | .type = CX231XX_VMUX_COMPOSITE1, |
153 | .vmux = CX231XX_VIN_2_1, | 153 | .vmux = CX231XX_VIN_2_1, |
154 | .amux = CX231XX_AMUX_LINE_IN, | 154 | .amux = CX231XX_AMUX_LINE_IN, |
155 | .gpio = 0, | 155 | .gpio = NULL, |
156 | }, { | 156 | }, { |
157 | .type = CX231XX_VMUX_SVIDEO, | 157 | .type = CX231XX_VMUX_SVIDEO, |
158 | .vmux = CX231XX_VIN_1_1 | | 158 | .vmux = CX231XX_VIN_1_1 | |
159 | (CX231XX_VIN_1_2 << 8) | | 159 | (CX231XX_VIN_1_2 << 8) | |
160 | CX25840_SVIDEO_ON, | 160 | CX25840_SVIDEO_ON, |
161 | .amux = CX231XX_AMUX_LINE_IN, | 161 | .amux = CX231XX_AMUX_LINE_IN, |
162 | .gpio = 0, | 162 | .gpio = NULL, |
163 | } | 163 | } |
164 | }, | 164 | }, |
165 | }, | 165 | }, |
@@ -856,8 +856,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) | |||
856 | 856 | ||
857 | if (dev->users) { | 857 | if (dev->users) { |
858 | cx231xx_warn | 858 | cx231xx_warn |
859 | ("device /dev/video%d is open! Deregistration and memory " | 859 | ("device %s is open! Deregistration and memory " |
860 | "deallocation are deferred on close.\n", dev->vdev->num); | 860 | "deallocation are deferred on close.\n", |
861 | video_device_node_name(dev->vdev)); | ||
861 | 862 | ||
862 | dev->state |= DEV_MISCONFIGURED; | 863 | dev->state |= DEV_MISCONFIGURED; |
863 | cx231xx_uninit_isoc(dev); | 864 | cx231xx_uninit_isoc(dev); |
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index 0d333e679f70..4a60dfbc347d 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c | |||
@@ -66,32 +66,6 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | |||
66 | static LIST_HEAD(cx231xx_devlist); | 66 | static LIST_HEAD(cx231xx_devlist); |
67 | static DEFINE_MUTEX(cx231xx_devlist_mutex); | 67 | static DEFINE_MUTEX(cx231xx_devlist_mutex); |
68 | 68 | ||
69 | struct cx231xx *cx231xx_get_device(int minor, | ||
70 | enum v4l2_buf_type *fh_type, int *has_radio) | ||
71 | { | ||
72 | struct cx231xx *h, *dev = NULL; | ||
73 | |||
74 | *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
75 | *has_radio = 0; | ||
76 | |||
77 | mutex_lock(&cx231xx_devlist_mutex); | ||
78 | list_for_each_entry(h, &cx231xx_devlist, devlist) { | ||
79 | if (h->vdev->minor == minor) | ||
80 | dev = h; | ||
81 | if (h->vbi_dev->minor == minor) { | ||
82 | dev = h; | ||
83 | *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
84 | } | ||
85 | if (h->radio_dev && h->radio_dev->minor == minor) { | ||
86 | dev = h; | ||
87 | *has_radio = 1; | ||
88 | } | ||
89 | } | ||
90 | mutex_unlock(&cx231xx_devlist_mutex); | ||
91 | |||
92 | return dev; | ||
93 | } | ||
94 | |||
95 | /* | 69 | /* |
96 | * cx231xx_realease_resources() | 70 | * cx231xx_realease_resources() |
97 | * unregisters the v4l2,i2c and usb devices | 71 | * unregisters the v4l2,i2c and usb devices |
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index cd135f01b9c1..15826f98b688 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c | |||
@@ -197,8 +197,7 @@ int cx231xx_ir_init(struct cx231xx *dev) | |||
197 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); | 197 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); |
198 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); | 198 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); |
199 | 199 | ||
200 | err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, | 200 | err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); |
201 | dev->board.ir_codes); | ||
202 | if (err < 0) | 201 | if (err < 0) |
203 | goto err_out_free; | 202 | goto err_out_free; |
204 | 203 | ||
@@ -217,7 +216,7 @@ int cx231xx_ir_init(struct cx231xx *dev) | |||
217 | cx231xx_ir_start(ir); | 216 | cx231xx_ir_start(ir); |
218 | 217 | ||
219 | /* all done */ | 218 | /* all done */ |
220 | err = input_register_device(ir->input); | 219 | err = ir_input_register(ir->input, dev->board.ir_codes); |
221 | if (err) | 220 | if (err) |
222 | goto err_out_stop; | 221 | goto err_out_stop; |
223 | 222 | ||
@@ -226,8 +225,6 @@ err_out_stop: | |||
226 | cx231xx_ir_stop(ir); | 225 | cx231xx_ir_stop(ir); |
227 | dev->ir = NULL; | 226 | dev->ir = NULL; |
228 | err_out_free: | 227 | err_out_free: |
229 | ir_input_free(input_dev); | ||
230 | input_free_device(input_dev); | ||
231 | kfree(ir); | 228 | kfree(ir); |
232 | return err; | 229 | return err; |
233 | } | 230 | } |
@@ -241,8 +238,7 @@ int cx231xx_ir_fini(struct cx231xx *dev) | |||
241 | return 0; | 238 | return 0; |
242 | 239 | ||
243 | cx231xx_ir_stop(ir); | 240 | cx231xx_ir_stop(ir); |
244 | ir_input_free(ir->input); | 241 | ir_input_unregister(ir->input); |
245 | input_unregister_device(ir->input); | ||
246 | kfree(ir); | 242 | kfree(ir); |
247 | 243 | ||
248 | /* done */ | 244 | /* done */ |
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index d095aa0d6d19..d4f546f11d74 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c | |||
@@ -1916,20 +1916,29 @@ static int radio_queryctrl(struct file *file, void *priv, | |||
1916 | */ | 1916 | */ |
1917 | static int cx231xx_v4l2_open(struct file *filp) | 1917 | static int cx231xx_v4l2_open(struct file *filp) |
1918 | { | 1918 | { |
1919 | int minor = video_devdata(filp)->minor; | ||
1920 | int errCode = 0, radio = 0; | 1919 | int errCode = 0, radio = 0; |
1921 | struct cx231xx *dev = NULL; | 1920 | struct video_device *vdev = video_devdata(filp); |
1921 | struct cx231xx *dev = video_drvdata(filp); | ||
1922 | struct cx231xx_fh *fh; | 1922 | struct cx231xx_fh *fh; |
1923 | enum v4l2_buf_type fh_type = 0; | 1923 | enum v4l2_buf_type fh_type = 0; |
1924 | 1924 | ||
1925 | dev = cx231xx_get_device(minor, &fh_type, &radio); | 1925 | switch (vdev->vfl_type) { |
1926 | if (NULL == dev) | 1926 | case VFL_TYPE_GRABBER: |
1927 | return -ENODEV; | 1927 | fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1928 | break; | ||
1929 | case VFL_TYPE_VBI: | ||
1930 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
1931 | break; | ||
1932 | case VFL_TYPE_RADIO: | ||
1933 | radio = 1; | ||
1934 | break; | ||
1935 | } | ||
1928 | 1936 | ||
1929 | mutex_lock(&dev->lock); | 1937 | mutex_lock(&dev->lock); |
1930 | 1938 | ||
1931 | cx231xx_videodbg("open minor=%d type=%s users=%d\n", | 1939 | cx231xx_videodbg("open dev=%s type=%s users=%d\n", |
1932 | minor, v4l2_type_names[fh_type], dev->users); | 1940 | video_device_node_name(vdev), v4l2_type_names[fh_type], |
1941 | dev->users); | ||
1933 | 1942 | ||
1934 | #if 0 | 1943 | #if 0 |
1935 | errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); | 1944 | errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); |
@@ -2020,25 +2029,25 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) | |||
2020 | /*FIXME: I2C IR should be disconnected */ | 2029 | /*FIXME: I2C IR should be disconnected */ |
2021 | 2030 | ||
2022 | if (dev->radio_dev) { | 2031 | if (dev->radio_dev) { |
2023 | if (-1 != dev->radio_dev->minor) | 2032 | if (video_is_registered(dev->radio_dev)) |
2024 | video_unregister_device(dev->radio_dev); | 2033 | video_unregister_device(dev->radio_dev); |
2025 | else | 2034 | else |
2026 | video_device_release(dev->radio_dev); | 2035 | video_device_release(dev->radio_dev); |
2027 | dev->radio_dev = NULL; | 2036 | dev->radio_dev = NULL; |
2028 | } | 2037 | } |
2029 | if (dev->vbi_dev) { | 2038 | if (dev->vbi_dev) { |
2030 | cx231xx_info("V4L2 device /dev/vbi%d deregistered\n", | 2039 | cx231xx_info("V4L2 device %s deregistered\n", |
2031 | dev->vbi_dev->num); | 2040 | video_device_node_name(dev->vbi_dev)); |
2032 | if (-1 != dev->vbi_dev->minor) | 2041 | if (video_is_registered(dev->vbi_dev)) |
2033 | video_unregister_device(dev->vbi_dev); | 2042 | video_unregister_device(dev->vbi_dev); |
2034 | else | 2043 | else |
2035 | video_device_release(dev->vbi_dev); | 2044 | video_device_release(dev->vbi_dev); |
2036 | dev->vbi_dev = NULL; | 2045 | dev->vbi_dev = NULL; |
2037 | } | 2046 | } |
2038 | if (dev->vdev) { | 2047 | if (dev->vdev) { |
2039 | cx231xx_info("V4L2 device /dev/video%d deregistered\n", | 2048 | cx231xx_info("V4L2 device %s deregistered\n", |
2040 | dev->vdev->num); | 2049 | video_device_node_name(dev->vdev)); |
2041 | if (-1 != dev->vdev->minor) | 2050 | if (video_is_registered(dev->vdev)) |
2042 | video_unregister_device(dev->vdev); | 2051 | video_unregister_device(dev->vdev); |
2043 | else | 2052 | else |
2044 | video_device_release(dev->vdev); | 2053 | video_device_release(dev->vdev); |
@@ -2268,7 +2277,6 @@ static const struct video_device cx231xx_video_template = { | |||
2268 | .fops = &cx231xx_v4l_fops, | 2277 | .fops = &cx231xx_v4l_fops, |
2269 | .release = video_device_release, | 2278 | .release = video_device_release, |
2270 | .ioctl_ops = &video_ioctl_ops, | 2279 | .ioctl_ops = &video_ioctl_ops, |
2271 | .minor = -1, | ||
2272 | .tvnorms = V4L2_STD_ALL, | 2280 | .tvnorms = V4L2_STD_ALL, |
2273 | .current_norm = V4L2_STD_PAL, | 2281 | .current_norm = V4L2_STD_PAL, |
2274 | }; | 2282 | }; |
@@ -2303,7 +2311,6 @@ static struct video_device cx231xx_radio_template = { | |||
2303 | .name = "cx231xx-radio", | 2311 | .name = "cx231xx-radio", |
2304 | .fops = &radio_fops, | 2312 | .fops = &radio_fops, |
2305 | .ioctl_ops = &radio_ioctl_ops, | 2313 | .ioctl_ops = &radio_ioctl_ops, |
2306 | .minor = -1, | ||
2307 | }; | 2314 | }; |
2308 | 2315 | ||
2309 | /******************************** usb interface ******************************/ | 2316 | /******************************** usb interface ******************************/ |
@@ -2319,13 +2326,13 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, | |||
2319 | return NULL; | 2326 | return NULL; |
2320 | 2327 | ||
2321 | *vfd = *template; | 2328 | *vfd = *template; |
2322 | vfd->minor = -1; | ||
2323 | vfd->v4l2_dev = &dev->v4l2_dev; | 2329 | vfd->v4l2_dev = &dev->v4l2_dev; |
2324 | vfd->release = video_device_release; | 2330 | vfd->release = video_device_release; |
2325 | vfd->debug = video_debug; | 2331 | vfd->debug = video_debug; |
2326 | 2332 | ||
2327 | snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); | 2333 | snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); |
2328 | 2334 | ||
2335 | video_set_drvdata(vfd, dev); | ||
2329 | return vfd; | 2336 | return vfd; |
2330 | } | 2337 | } |
2331 | 2338 | ||
@@ -2374,8 +2381,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) | |||
2374 | return ret; | 2381 | return ret; |
2375 | } | 2382 | } |
2376 | 2383 | ||
2377 | cx231xx_info("%s/0: registered device video%d [v4l2]\n", | 2384 | cx231xx_info("%s/0: registered device %s [v4l2]\n", |
2378 | dev->name, dev->vdev->num); | 2385 | dev->name, video_device_node_name(dev->vdev)); |
2379 | 2386 | ||
2380 | /* Initialize VBI template */ | 2387 | /* Initialize VBI template */ |
2381 | memcpy(&cx231xx_vbi_template, &cx231xx_video_template, | 2388 | memcpy(&cx231xx_vbi_template, &cx231xx_video_template, |
@@ -2393,8 +2400,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) | |||
2393 | return ret; | 2400 | return ret; |
2394 | } | 2401 | } |
2395 | 2402 | ||
2396 | cx231xx_info("%s/0: registered device vbi%d\n", | 2403 | cx231xx_info("%s/0: registered device %s\n", |
2397 | dev->name, dev->vbi_dev->num); | 2404 | dev->name, video_device_node_name(dev->vbi_dev)); |
2398 | 2405 | ||
2399 | if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { | 2406 | if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { |
2400 | dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, | 2407 | dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, |
@@ -2409,12 +2416,13 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) | |||
2409 | cx231xx_errdev("can't register radio device\n"); | 2416 | cx231xx_errdev("can't register radio device\n"); |
2410 | return ret; | 2417 | return ret; |
2411 | } | 2418 | } |
2412 | cx231xx_info("Registered radio device as /dev/radio%d\n", | 2419 | cx231xx_info("Registered radio device as %s\n", |
2413 | dev->radio_dev->num); | 2420 | video_device_node_name(dev->radio_dev)); |
2414 | } | 2421 | } |
2415 | 2422 | ||
2416 | cx231xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | 2423 | cx231xx_info("V4L2 device registered as %s and %s\n", |
2417 | dev->vdev->num, dev->vbi_dev->num); | 2424 | video_device_node_name(dev->vdev), |
2425 | video_device_node_name(dev->vbi_dev)); | ||
2418 | 2426 | ||
2419 | return 0; | 2427 | return 0; |
2420 | } | 2428 | } |
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 64e2ddd3c401..17d4d1a800ce 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h | |||
@@ -689,8 +689,6 @@ void cx231xx_release_analog_resources(struct cx231xx *dev); | |||
689 | int cx231xx_register_analog_devices(struct cx231xx *dev); | 689 | int cx231xx_register_analog_devices(struct cx231xx *dev); |
690 | void cx231xx_remove_from_devlist(struct cx231xx *dev); | 690 | void cx231xx_remove_from_devlist(struct cx231xx *dev); |
691 | void cx231xx_add_into_devlist(struct cx231xx *dev); | 691 | void cx231xx_add_into_devlist(struct cx231xx *dev); |
692 | struct cx231xx *cx231xx_get_device(int minor, | ||
693 | enum v4l2_buf_type *fh_type, int *has_radio); | ||
694 | void cx231xx_init_extension(struct cx231xx *dev); | 692 | void cx231xx_init_extension(struct cx231xx *dev); |
695 | void cx231xx_close_extension(struct cx231xx *dev); | 693 | void cx231xx_close_extension(struct cx231xx *dev); |
696 | 694 | ||
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c index c04222ffb286..d4a9d2c5947c 100644 --- a/drivers/media/video/cx23885/cimax2.c +++ b/drivers/media/video/cx23885/cimax2.c | |||
@@ -53,6 +53,8 @@ | |||
53 | #define NETUP_CI_CTL 0x04 | 53 | #define NETUP_CI_CTL 0x04 |
54 | #define NETUP_CI_RD 1 | 54 | #define NETUP_CI_RD 1 |
55 | 55 | ||
56 | #define NETUP_IRQ_DETAM 0x1 | ||
57 | #define NETUP_IRQ_IRQAM 0x4 | ||
56 | 58 | ||
57 | static unsigned int ci_dbg; | 59 | static unsigned int ci_dbg; |
58 | module_param(ci_dbg, int, 0644); | 60 | module_param(ci_dbg, int, 0644); |
@@ -73,6 +75,9 @@ struct netup_ci_state { | |||
73 | int status; | 75 | int status; |
74 | struct work_struct work; | 76 | struct work_struct work; |
75 | void *priv; | 77 | void *priv; |
78 | u8 current_irq_mode; | ||
79 | int current_ci_flag; | ||
80 | unsigned long next_status_checked_time; | ||
76 | }; | 81 | }; |
77 | 82 | ||
78 | 83 | ||
@@ -169,24 +174,26 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
169 | if (0 != slot) | 174 | if (0 != slot) |
170 | return -EINVAL; | 175 | return -EINVAL; |
171 | 176 | ||
172 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | 177 | if (state->current_ci_flag != flag) { |
173 | 0, &store, 1); | 178 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, |
174 | if (ret != 0) | 179 | 0, &store, 1); |
175 | return ret; | 180 | if (ret != 0) |
181 | return ret; | ||
176 | 182 | ||
177 | store &= ~0x0c; | 183 | store &= ~0x0c; |
178 | store |= flag; | 184 | store |= flag; |
179 | 185 | ||
180 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | 186 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, |
181 | 0, &store, 1); | 187 | 0, &store, 1); |
182 | if (ret != 0) | 188 | if (ret != 0) |
183 | return ret; | 189 | return ret; |
190 | }; | ||
191 | state->current_ci_flag = flag; | ||
184 | 192 | ||
185 | mutex_lock(&dev->gpio_lock); | 193 | mutex_lock(&dev->gpio_lock); |
186 | 194 | ||
187 | /* write addr */ | 195 | /* write addr */ |
188 | cx_write(MC417_OEN, NETUP_EN_ALL); | 196 | cx_write(MC417_OEN, NETUP_EN_ALL); |
189 | msleep(2); | ||
190 | cx_write(MC417_RWD, NETUP_CTRL_OFF | | 197 | cx_write(MC417_RWD, NETUP_CTRL_OFF | |
191 | NETUP_ADLO | (0xff & addr)); | 198 | NETUP_ADLO | (0xff & addr)); |
192 | cx_clear(MC417_RWD, NETUP_ADLO); | 199 | cx_clear(MC417_RWD, NETUP_ADLO); |
@@ -196,7 +203,6 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
196 | 203 | ||
197 | if (read) { /* data in */ | 204 | if (read) { /* data in */ |
198 | cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); | 205 | cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); |
199 | msleep(2); | ||
200 | } else /* data out */ | 206 | } else /* data out */ |
201 | cx_write(MC417_RWD, NETUP_CTRL_OFF | data); | 207 | cx_write(MC417_RWD, NETUP_CTRL_OFF | data); |
202 | 208 | ||
@@ -213,8 +219,8 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, | |||
213 | if (mem < 0) | 219 | if (mem < 0) |
214 | return -EREMOTEIO; | 220 | return -EREMOTEIO; |
215 | 221 | ||
216 | ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, | 222 | ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__, |
217 | (read) ? "read" : "write", addr, | 223 | (read) ? "read" : "write", state->ci_i2c_addr, addr, |
218 | (flag == NETUP_CI_CTL) ? "ctl" : "mem", | 224 | (flag == NETUP_CI_CTL) ? "ctl" : "mem", |
219 | (read) ? mem : data); | 225 | (read) ? mem : data); |
220 | 226 | ||
@@ -283,14 +289,39 @@ int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) | |||
283 | return 0; | 289 | return 0; |
284 | } | 290 | } |
285 | 291 | ||
292 | int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) | ||
293 | { | ||
294 | struct netup_ci_state *state = en50221->data; | ||
295 | int ret; | ||
296 | |||
297 | if (irq_mode == state->current_irq_mode) | ||
298 | return 0; | ||
299 | |||
300 | ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n", | ||
301 | __func__, state->ci_i2c_addr, irq_mode); | ||
302 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
303 | 0x1b, &irq_mode, 1); | ||
304 | |||
305 | if (ret != 0) | ||
306 | return ret; | ||
307 | |||
308 | state->current_irq_mode = irq_mode; | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
286 | int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) | 313 | int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) |
287 | { | 314 | { |
288 | struct netup_ci_state *state = en50221->data; | 315 | struct netup_ci_state *state = en50221->data; |
289 | u8 buf = 0x60; | 316 | u8 buf; |
290 | 317 | ||
291 | if (0 != slot) | 318 | if (0 != slot) |
292 | return -EINVAL; | 319 | return -EINVAL; |
293 | 320 | ||
321 | netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
322 | 0, &buf, 1); | ||
323 | buf |= 0x60; | ||
324 | |||
294 | return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | 325 | return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, |
295 | 0, &buf, 1); | 326 | 0, &buf, 1); |
296 | } | 327 | } |
@@ -303,21 +334,35 @@ static void netup_read_ci_status(struct work_struct *work) | |||
303 | u8 buf[33]; | 334 | u8 buf[33]; |
304 | int ret; | 335 | int ret; |
305 | 336 | ||
306 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | 337 | /* CAM module IRQ processing. fast operation */ |
307 | 0, &buf[0], 33); | 338 | dvb_ca_en50221_frda_irq(&state->ca, 0); |
308 | 339 | ||
309 | if (ret != 0) | 340 | /* CAM module INSERT/REMOVE processing. slow operation because of i2c |
310 | return; | 341 | * transfers */ |
342 | if (time_after(jiffies, state->next_status_checked_time) | ||
343 | || !state->status) { | ||
344 | ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, | ||
345 | 0, &buf[0], 33); | ||
346 | |||
347 | state->next_status_checked_time = jiffies | ||
348 | + msecs_to_jiffies(1000); | ||
349 | |||
350 | if (ret != 0) | ||
351 | return; | ||
311 | 352 | ||
312 | ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, " | 353 | ci_dbg_print("%s: Slot Status Addr=[0x%04x], " |
313 | "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0], | 354 | "Reg=[0x%02x], data=%02x, " |
314 | buf[32]); | 355 | "TS config = %02x\n", __func__, |
356 | state->ci_i2c_addr, 0, buf[0], | ||
357 | buf[0]); | ||
315 | 358 | ||
316 | if (buf[0] & 1) | 359 | |
317 | state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | | 360 | if (buf[0] & 1) |
318 | DVB_CA_EN50221_POLL_CAM_READY; | 361 | state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | |
319 | else | 362 | DVB_CA_EN50221_POLL_CAM_READY; |
320 | state->status = 0; | 363 | else |
364 | state->status = 0; | ||
365 | }; | ||
321 | } | 366 | } |
322 | 367 | ||
323 | /* CI irq handler */ | 368 | /* CI irq handler */ |
@@ -347,6 +392,9 @@ int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open | |||
347 | if (0 != slot) | 392 | if (0 != slot) |
348 | return -EINVAL; | 393 | return -EINVAL; |
349 | 394 | ||
395 | netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | NETUP_IRQ_IRQAM) | ||
396 | : NETUP_IRQ_DETAM); | ||
397 | |||
350 | return state->status; | 398 | return state->status; |
351 | } | 399 | } |
352 | 400 | ||
@@ -381,8 +429,8 @@ int netup_ci_init(struct cx23885_tsport *port) | |||
381 | 0x01, /* power on (use it like store place) */ | 429 | 0x01, /* power on (use it like store place) */ |
382 | 0x00, /* RFU */ | 430 | 0x00, /* RFU */ |
383 | 0x00, /* int status read only */ | 431 | 0x00, /* int status read only */ |
384 | 0x01, /* all int unmasked */ | 432 | NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */ |
385 | 0x04, /* int config */ | 433 | 0x05, /* EXTINT=active-high, INT=push-pull */ |
386 | 0x00, /* USCG1 */ | 434 | 0x00, /* USCG1 */ |
387 | 0x04, /* ack active low */ | 435 | 0x04, /* ack active low */ |
388 | 0x00, /* LOCK = 0 */ | 436 | 0x00, /* LOCK = 0 */ |
@@ -422,6 +470,7 @@ int netup_ci_init(struct cx23885_tsport *port) | |||
422 | state->ca.poll_slot_status = netup_poll_ci_slot_status; | 470 | state->ca.poll_slot_status = netup_poll_ci_slot_status; |
423 | state->ca.data = state; | 471 | state->ca.data = state; |
424 | state->priv = port; | 472 | state->priv = port; |
473 | state->current_irq_mode = NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM; | ||
425 | 474 | ||
426 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, | 475 | ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, |
427 | 0, &cimax_init[0], 34); | 476 | 0, &cimax_init[0], 34); |
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 0eed852c61e9..88c0d2481118 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c | |||
@@ -1568,28 +1568,11 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
1568 | 1568 | ||
1569 | static int mpeg_open(struct file *file) | 1569 | static int mpeg_open(struct file *file) |
1570 | { | 1570 | { |
1571 | int minor = video_devdata(file)->minor; | 1571 | struct cx23885_dev *dev = video_drvdata(file); |
1572 | struct cx23885_dev *h, *dev = NULL; | ||
1573 | struct list_head *list; | ||
1574 | struct cx23885_fh *fh; | 1572 | struct cx23885_fh *fh; |
1575 | 1573 | ||
1576 | dprintk(2, "%s()\n", __func__); | 1574 | dprintk(2, "%s()\n", __func__); |
1577 | 1575 | ||
1578 | lock_kernel(); | ||
1579 | list_for_each(list, &cx23885_devlist) { | ||
1580 | h = list_entry(list, struct cx23885_dev, devlist); | ||
1581 | if (h->v4l_device && | ||
1582 | h->v4l_device->minor == minor) { | ||
1583 | dev = h; | ||
1584 | break; | ||
1585 | } | ||
1586 | } | ||
1587 | |||
1588 | if (dev == NULL) { | ||
1589 | unlock_kernel(); | ||
1590 | return -ENODEV; | ||
1591 | } | ||
1592 | |||
1593 | /* allocate + initialize per filehandle data */ | 1576 | /* allocate + initialize per filehandle data */ |
1594 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 1577 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
1595 | if (NULL == fh) { | 1578 | if (NULL == fh) { |
@@ -1597,6 +1580,8 @@ static int mpeg_open(struct file *file) | |||
1597 | return -ENOMEM; | 1580 | return -ENOMEM; |
1598 | } | 1581 | } |
1599 | 1582 | ||
1583 | lock_kernel(); | ||
1584 | |||
1600 | file->private_data = fh; | 1585 | file->private_data = fh; |
1601 | fh->dev = dev; | 1586 | fh->dev = dev; |
1602 | 1587 | ||
@@ -1736,7 +1721,6 @@ static struct video_device cx23885_mpeg_template = { | |||
1736 | .name = "cx23885", | 1721 | .name = "cx23885", |
1737 | .fops = &mpeg_fops, | 1722 | .fops = &mpeg_fops, |
1738 | .ioctl_ops = &mpeg_ioctl_ops, | 1723 | .ioctl_ops = &mpeg_ioctl_ops, |
1739 | .minor = -1, | ||
1740 | .tvnorms = CX23885_NORMS, | 1724 | .tvnorms = CX23885_NORMS, |
1741 | .current_norm = V4L2_STD_NTSC_M, | 1725 | .current_norm = V4L2_STD_NTSC_M, |
1742 | }; | 1726 | }; |
@@ -1746,7 +1730,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev) | |||
1746 | dprintk(1, "%s()\n", __func__); | 1730 | dprintk(1, "%s()\n", __func__); |
1747 | 1731 | ||
1748 | if (dev->v4l_device) { | 1732 | if (dev->v4l_device) { |
1749 | if (-1 != dev->v4l_device->minor) | 1733 | if (video_is_registered(dev->v4l_device)) |
1750 | video_unregister_device(dev->v4l_device); | 1734 | video_unregister_device(dev->v4l_device); |
1751 | else | 1735 | else |
1752 | video_device_release(dev->v4l_device); | 1736 | video_device_release(dev->v4l_device); |
@@ -1803,6 +1787,7 @@ int cx23885_417_register(struct cx23885_dev *dev) | |||
1803 | /* Allocate and initialize V4L video device */ | 1787 | /* Allocate and initialize V4L video device */ |
1804 | dev->v4l_device = cx23885_video_dev_alloc(tsport, | 1788 | dev->v4l_device = cx23885_video_dev_alloc(tsport, |
1805 | dev->pci, &cx23885_mpeg_template, "mpeg"); | 1789 | dev->pci, &cx23885_mpeg_template, "mpeg"); |
1790 | video_set_drvdata(dev->v4l_device, dev); | ||
1806 | err = video_register_device(dev->v4l_device, | 1791 | err = video_register_device(dev->v4l_device, |
1807 | VFL_TYPE_GRABBER, -1); | 1792 | VFL_TYPE_GRABBER, -1); |
1808 | if (err < 0) { | 1793 | if (err < 0) { |
@@ -1810,8 +1795,8 @@ int cx23885_417_register(struct cx23885_dev *dev) | |||
1810 | return err; | 1795 | return err; |
1811 | } | 1796 | } |
1812 | 1797 | ||
1813 | printk(KERN_INFO "%s: registered device video%d [mpeg]\n", | 1798 | printk(KERN_INFO "%s: registered device %s [mpeg]\n", |
1814 | dev->name, dev->v4l_device->num); | 1799 | dev->name, video_device_node_name(dev->v4l_device)); |
1815 | 1800 | ||
1816 | return 0; | 1801 | return 0; |
1817 | } | 1802 | } |
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 04b12d27bc13..0dde57e96d30 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -55,9 +55,6 @@ MODULE_PARM_DESC(card, "card type"); | |||
55 | 55 | ||
56 | static unsigned int cx23885_devcount; | 56 | static unsigned int cx23885_devcount; |
57 | 57 | ||
58 | static DEFINE_MUTEX(devlist); | ||
59 | LIST_HEAD(cx23885_devlist); | ||
60 | |||
61 | #define NO_SYNC_LINE (-1U) | 58 | #define NO_SYNC_LINE (-1U) |
62 | 59 | ||
63 | /* FIXME, these allocations will change when | 60 | /* FIXME, these allocations will change when |
@@ -785,10 +782,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) | |||
785 | dev->nr = cx23885_devcount++; | 782 | dev->nr = cx23885_devcount++; |
786 | sprintf(dev->name, "cx23885[%d]", dev->nr); | 783 | sprintf(dev->name, "cx23885[%d]", dev->nr); |
787 | 784 | ||
788 | mutex_lock(&devlist); | ||
789 | list_add_tail(&dev->devlist, &cx23885_devlist); | ||
790 | mutex_unlock(&devlist); | ||
791 | |||
792 | /* Configure the internal memory */ | 785 | /* Configure the internal memory */ |
793 | if (dev->pci->device == 0x8880) { | 786 | if (dev->pci->device == 0x8880) { |
794 | /* Could be 887 or 888, assume a default */ | 787 | /* Could be 887 or 888, assume a default */ |
@@ -2008,10 +2001,6 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) | |||
2008 | /* unregister stuff */ | 2001 | /* unregister stuff */ |
2009 | free_irq(pci_dev->irq, dev); | 2002 | free_irq(pci_dev->irq, dev); |
2010 | 2003 | ||
2011 | mutex_lock(&devlist); | ||
2012 | list_del(&dev->devlist); | ||
2013 | mutex_unlock(&devlist); | ||
2014 | |||
2015 | cx23885_dev_unregister(dev); | 2004 | cx23885_dev_unregister(dev); |
2016 | v4l2_device_unregister(v4l2_dev); | 2005 | v4l2_device_unregister(v4l2_dev); |
2017 | kfree(dev); | 2006 | kfree(dev); |
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 469e083dd5f8..768eec92ccf9 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c | |||
@@ -377,7 +377,7 @@ int cx23885_input_init(struct cx23885_dev *dev) | |||
377 | cx23885_boards[dev->board].name); | 377 | cx23885_boards[dev->board].name); |
378 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); | 378 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); |
379 | 379 | ||
380 | ret = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 380 | ret = ir_input_init(input_dev, &ir->ir, ir_type); |
381 | if (ret < 0) | 381 | if (ret < 0) |
382 | goto err_out_free; | 382 | goto err_out_free; |
383 | 383 | ||
@@ -397,7 +397,7 @@ int cx23885_input_init(struct cx23885_dev *dev) | |||
397 | dev->ir_input = ir; | 397 | dev->ir_input = ir; |
398 | cx23885_input_ir_start(dev); | 398 | cx23885_input_ir_start(dev); |
399 | 399 | ||
400 | ret = input_register_device(ir->dev); | 400 | ret = ir_input_register(ir->dev, ir_codes); |
401 | if (ret) | 401 | if (ret) |
402 | goto err_out_stop; | 402 | goto err_out_stop; |
403 | 403 | ||
@@ -407,8 +407,6 @@ err_out_stop: | |||
407 | cx23885_input_ir_stop(dev); | 407 | cx23885_input_ir_stop(dev); |
408 | dev->ir_input = NULL; | 408 | dev->ir_input = NULL; |
409 | err_out_free: | 409 | err_out_free: |
410 | ir_input_free(input_dev); | ||
411 | input_free_device(input_dev); | ||
412 | kfree(ir); | 410 | kfree(ir); |
413 | return ret; | 411 | return ret; |
414 | } | 412 | } |
@@ -420,8 +418,7 @@ void cx23885_input_fini(struct cx23885_dev *dev) | |||
420 | 418 | ||
421 | if (dev->ir_input == NULL) | 419 | if (dev->ir_input == NULL) |
422 | return; | 420 | return; |
423 | ir_input_free(dev->ir_input->dev); | 421 | ir_input_unregister(dev->ir_input->dev); |
424 | input_unregister_device(dev->ir_input->dev); | ||
425 | kfree(dev->ir_input); | 422 | kfree(dev->ir_input); |
426 | dev->ir_input = NULL; | 423 | dev->ir_input = NULL; |
427 | } | 424 | } |
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 8b372b4f0de2..8934d61cf660 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c | |||
@@ -318,11 +318,11 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, | |||
318 | if (NULL == vfd) | 318 | if (NULL == vfd) |
319 | return NULL; | 319 | return NULL; |
320 | *vfd = *template; | 320 | *vfd = *template; |
321 | vfd->minor = -1; | ||
322 | vfd->v4l2_dev = &dev->v4l2_dev; | 321 | vfd->v4l2_dev = &dev->v4l2_dev; |
323 | vfd->release = video_device_release; | 322 | vfd->release = video_device_release; |
324 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | 323 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", |
325 | dev->name, type, cx23885_boards[dev->board].name); | 324 | dev->name, type, cx23885_boards[dev->board].name); |
325 | video_set_drvdata(vfd, dev); | ||
326 | return vfd; | 326 | return vfd; |
327 | } | 327 | } |
328 | 328 | ||
@@ -716,46 +716,34 @@ static int get_resource(struct cx23885_fh *fh) | |||
716 | 716 | ||
717 | static int video_open(struct file *file) | 717 | static int video_open(struct file *file) |
718 | { | 718 | { |
719 | int minor = video_devdata(file)->minor; | 719 | struct video_device *vdev = video_devdata(file); |
720 | struct cx23885_dev *h, *dev = NULL; | 720 | struct cx23885_dev *dev = video_drvdata(file); |
721 | struct cx23885_fh *fh; | 721 | struct cx23885_fh *fh; |
722 | struct list_head *list; | ||
723 | enum v4l2_buf_type type = 0; | 722 | enum v4l2_buf_type type = 0; |
724 | int radio = 0; | 723 | int radio = 0; |
725 | 724 | ||
726 | lock_kernel(); | 725 | switch (vdev->vfl_type) { |
727 | list_for_each(list, &cx23885_devlist) { | 726 | case VFL_TYPE_GRABBER: |
728 | h = list_entry(list, struct cx23885_dev, devlist); | 727 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
729 | if (h->video_dev && | 728 | break; |
730 | h->video_dev->minor == minor) { | 729 | case VFL_TYPE_VBI: |
731 | dev = h; | 730 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
732 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 731 | break; |
733 | } | 732 | case VFL_TYPE_RADIO: |
734 | if (h->vbi_dev && | 733 | radio = 1; |
735 | h->vbi_dev->minor == minor) { | 734 | break; |
736 | dev = h; | ||
737 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
738 | } | ||
739 | if (h->radio_dev && | ||
740 | h->radio_dev->minor == minor) { | ||
741 | radio = 1; | ||
742 | dev = h; | ||
743 | } | ||
744 | } | ||
745 | if (NULL == dev) { | ||
746 | unlock_kernel(); | ||
747 | return -ENODEV; | ||
748 | } | 735 | } |
749 | 736 | ||
750 | dprintk(1, "open minor=%d radio=%d type=%s\n", | 737 | dprintk(1, "open dev=%s radio=%d type=%s\n", |
751 | minor, radio, v4l2_type_names[type]); | 738 | video_device_node_name(vdev), radio, v4l2_type_names[type]); |
752 | 739 | ||
753 | /* allocate + initialize per filehandle data */ | 740 | /* allocate + initialize per filehandle data */ |
754 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 741 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
755 | if (NULL == fh) { | 742 | if (NULL == fh) |
756 | unlock_kernel(); | ||
757 | return -ENOMEM; | 743 | return -ENOMEM; |
758 | } | 744 | |
745 | lock_kernel(); | ||
746 | |||
759 | file->private_data = fh; | 747 | file->private_data = fh; |
760 | fh->dev = dev; | 748 | fh->dev = dev; |
761 | fh->radio = radio; | 749 | fh->radio = radio; |
@@ -1441,7 +1429,6 @@ static struct video_device cx23885_vbi_template; | |||
1441 | static struct video_device cx23885_video_template = { | 1429 | static struct video_device cx23885_video_template = { |
1442 | .name = "cx23885-video", | 1430 | .name = "cx23885-video", |
1443 | .fops = &video_fops, | 1431 | .fops = &video_fops, |
1444 | .minor = -1, | ||
1445 | .ioctl_ops = &video_ioctl_ops, | 1432 | .ioctl_ops = &video_ioctl_ops, |
1446 | .tvnorms = CX23885_NORMS, | 1433 | .tvnorms = CX23885_NORMS, |
1447 | .current_norm = V4L2_STD_NTSC_M, | 1434 | .current_norm = V4L2_STD_NTSC_M, |
@@ -1461,7 +1448,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) | |||
1461 | cx_clear(PCI_INT_MSK, 1); | 1448 | cx_clear(PCI_INT_MSK, 1); |
1462 | 1449 | ||
1463 | if (dev->video_dev) { | 1450 | if (dev->video_dev) { |
1464 | if (-1 != dev->video_dev->minor) | 1451 | if (video_is_registered(dev->video_dev)) |
1465 | video_unregister_device(dev->video_dev); | 1452 | video_unregister_device(dev->video_dev); |
1466 | else | 1453 | else |
1467 | video_device_release(dev->video_dev); | 1454 | video_device_release(dev->video_dev); |
@@ -1532,8 +1519,8 @@ int cx23885_video_register(struct cx23885_dev *dev) | |||
1532 | dev->name); | 1519 | dev->name); |
1533 | goto fail_unreg; | 1520 | goto fail_unreg; |
1534 | } | 1521 | } |
1535 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", | 1522 | printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", |
1536 | dev->name, dev->video_dev->num); | 1523 | dev->name, video_device_node_name(dev->video_dev)); |
1537 | /* initial device configuration */ | 1524 | /* initial device configuration */ |
1538 | mutex_lock(&dev->lock); | 1525 | mutex_lock(&dev->lock); |
1539 | cx23885_set_tvnorm(dev, dev->tvnorm); | 1526 | cx23885_set_tvnorm(dev, dev->tvnorm); |
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index fa744764dc8b..08b3f6b136a0 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h | |||
@@ -303,7 +303,6 @@ struct cx23885_tsport { | |||
303 | }; | 303 | }; |
304 | 304 | ||
305 | struct cx23885_dev { | 305 | struct cx23885_dev { |
306 | struct list_head devlist; | ||
307 | atomic_t refcount; | 306 | atomic_t refcount; |
308 | struct v4l2_device v4l2_dev; | 307 | struct v4l2_device v4l2_dev; |
309 | 308 | ||
@@ -399,8 +398,6 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) | |||
399 | 398 | ||
400 | extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); | 399 | extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); |
401 | 400 | ||
402 | extern struct list_head cx23885_devlist; | ||
403 | |||
404 | #define SRAM_CH01 0 /* Video A */ | 401 | #define SRAM_CH01 0 /* Video A */ |
405 | #define SRAM_CH02 1 /* VBI A */ | 402 | #define SRAM_CH02 1 /* VBI A */ |
406 | #define SRAM_CH03 2 /* Video B */ | 403 | #define SRAM_CH03 2 /* Video B */ |
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fbdc1cde56a6..6fe30e6c4262 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -1048,21 +1048,15 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) | |||
1048 | 1048 | ||
1049 | static int mpeg_open(struct file *file) | 1049 | static int mpeg_open(struct file *file) |
1050 | { | 1050 | { |
1051 | int minor = video_devdata(file)->minor; | 1051 | struct video_device *vdev = video_devdata(file); |
1052 | struct cx8802_dev *dev = NULL; | 1052 | struct cx8802_dev *dev = video_drvdata(file); |
1053 | struct cx8802_fh *fh; | 1053 | struct cx8802_fh *fh; |
1054 | struct cx8802_driver *drv = NULL; | 1054 | struct cx8802_driver *drv = NULL; |
1055 | int err; | 1055 | int err; |
1056 | 1056 | ||
1057 | lock_kernel(); | ||
1058 | dev = cx8802_get_device(minor); | ||
1059 | |||
1060 | dprintk( 1, "%s\n", __func__); | 1057 | dprintk( 1, "%s\n", __func__); |
1061 | 1058 | ||
1062 | if (dev == NULL) { | 1059 | lock_kernel(); |
1063 | unlock_kernel(); | ||
1064 | return -ENODEV; | ||
1065 | } | ||
1066 | 1060 | ||
1067 | /* Make sure we can acquire the hardware */ | 1061 | /* Make sure we can acquire the hardware */ |
1068 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | 1062 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); |
@@ -1081,7 +1075,7 @@ static int mpeg_open(struct file *file) | |||
1081 | unlock_kernel(); | 1075 | unlock_kernel(); |
1082 | return -EINVAL; | 1076 | return -EINVAL; |
1083 | } | 1077 | } |
1084 | dprintk(1,"open minor=%d\n",minor); | 1078 | dprintk(1, "open dev=%s\n", video_device_node_name(vdev)); |
1085 | 1079 | ||
1086 | /* allocate + initialize per filehandle data */ | 1080 | /* allocate + initialize per filehandle data */ |
1087 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 1081 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
@@ -1129,10 +1123,6 @@ static int mpeg_release(struct file *file) | |||
1129 | kfree(fh); | 1123 | kfree(fh); |
1130 | 1124 | ||
1131 | /* Make sure we release the hardware */ | 1125 | /* Make sure we release the hardware */ |
1132 | dev = cx8802_get_device(video_devdata(file)->minor); | ||
1133 | if (dev == NULL) | ||
1134 | return -ENODEV; | ||
1135 | |||
1136 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | 1126 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); |
1137 | if (drv) | 1127 | if (drv) |
1138 | drv->request_release(drv); | 1128 | drv->request_release(drv); |
@@ -1220,7 +1210,6 @@ static struct video_device cx8802_mpeg_template = { | |||
1220 | .name = "cx8802", | 1210 | .name = "cx8802", |
1221 | .fops = &mpeg_fops, | 1211 | .fops = &mpeg_fops, |
1222 | .ioctl_ops = &mpeg_ioctl_ops, | 1212 | .ioctl_ops = &mpeg_ioctl_ops, |
1223 | .minor = -1, | ||
1224 | .tvnorms = CX88_NORMS, | 1213 | .tvnorms = CX88_NORMS, |
1225 | .current_norm = V4L2_STD_NTSC_M, | 1214 | .current_norm = V4L2_STD_NTSC_M, |
1226 | }; | 1215 | }; |
@@ -1276,7 +1265,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) | |||
1276 | static void blackbird_unregister_video(struct cx8802_dev *dev) | 1265 | static void blackbird_unregister_video(struct cx8802_dev *dev) |
1277 | { | 1266 | { |
1278 | if (dev->mpeg_dev) { | 1267 | if (dev->mpeg_dev) { |
1279 | if (-1 != dev->mpeg_dev->minor) | 1268 | if (video_is_registered(dev->mpeg_dev)) |
1280 | video_unregister_device(dev->mpeg_dev); | 1269 | video_unregister_device(dev->mpeg_dev); |
1281 | else | 1270 | else |
1282 | video_device_release(dev->mpeg_dev); | 1271 | video_device_release(dev->mpeg_dev); |
@@ -1290,14 +1279,15 @@ static int blackbird_register_video(struct cx8802_dev *dev) | |||
1290 | 1279 | ||
1291 | dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, | 1280 | dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, |
1292 | &cx8802_mpeg_template,"mpeg"); | 1281 | &cx8802_mpeg_template,"mpeg"); |
1282 | video_set_drvdata(dev->mpeg_dev, dev); | ||
1293 | err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); | 1283 | err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); |
1294 | if (err < 0) { | 1284 | if (err < 0) { |
1295 | printk(KERN_INFO "%s/2: can't register mpeg device\n", | 1285 | printk(KERN_INFO "%s/2: can't register mpeg device\n", |
1296 | dev->core->name); | 1286 | dev->core->name); |
1297 | return err; | 1287 | return err; |
1298 | } | 1288 | } |
1299 | printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n", | 1289 | printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", |
1300 | dev->core->name, dev->mpeg_dev->num); | 1290 | dev->core->name, video_device_node_name(dev->mpeg_dev)); |
1301 | return 0; | 1291 | return 0; |
1302 | } | 1292 | } |
1303 | 1293 | ||
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 92b8cdf9fb81..f9fda18b410c 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c | |||
@@ -360,7 +360,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) | |||
360 | snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); | 360 | snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); |
361 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); | 361 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); |
362 | 362 | ||
363 | err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 363 | err = ir_input_init(input_dev, &ir->ir, ir_type); |
364 | if (err < 0) | 364 | if (err < 0) |
365 | goto err_out_free; | 365 | goto err_out_free; |
366 | 366 | ||
@@ -383,7 +383,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) | |||
383 | cx88_ir_start(core, ir); | 383 | cx88_ir_start(core, ir); |
384 | 384 | ||
385 | /* all done */ | 385 | /* all done */ |
386 | err = input_register_device(ir->input); | 386 | err = ir_input_register(ir->input, ir_codes); |
387 | if (err) | 387 | if (err) |
388 | goto err_out_stop; | 388 | goto err_out_stop; |
389 | 389 | ||
@@ -393,8 +393,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) | |||
393 | cx88_ir_stop(core, ir); | 393 | cx88_ir_stop(core, ir); |
394 | core->ir = NULL; | 394 | core->ir = NULL; |
395 | err_out_free: | 395 | err_out_free: |
396 | ir_input_free(input_dev); | ||
397 | input_free_device(input_dev); | ||
398 | kfree(ir); | 396 | kfree(ir); |
399 | return err; | 397 | return err; |
400 | } | 398 | } |
@@ -408,8 +406,7 @@ int cx88_ir_fini(struct cx88_core *core) | |||
408 | return 0; | 406 | return 0; |
409 | 407 | ||
410 | cx88_ir_stop(core, ir); | 408 | cx88_ir_stop(core, ir); |
411 | ir_input_free(ir->input); | 409 | ir_input_unregister(ir->input); |
412 | input_unregister_device(ir->input); | ||
413 | kfree(ir); | 410 | kfree(ir); |
414 | 411 | ||
415 | /* done */ | 412 | /* done */ |
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index de9ff0fc741f..bb5104893411 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c | |||
@@ -580,21 +580,6 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) | |||
580 | return 0; | 580 | return 0; |
581 | } | 581 | } |
582 | 582 | ||
583 | #if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \ | ||
584 | defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE) | ||
585 | struct cx8802_dev *cx8802_get_device(int minor) | ||
586 | { | ||
587 | struct cx8802_dev *dev; | ||
588 | |||
589 | list_for_each_entry(dev, &cx8802_devlist, devlist) | ||
590 | if (dev->mpeg_dev && dev->mpeg_dev->minor == minor) | ||
591 | return dev; | ||
592 | |||
593 | return NULL; | ||
594 | } | ||
595 | EXPORT_SYMBOL(cx8802_get_device); | ||
596 | #endif | ||
597 | |||
598 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) | 583 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) |
599 | { | 584 | { |
600 | struct cx8802_driver *d; | 585 | struct cx8802_driver *d; |
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index d7e8fcee559c..48c450f4a85a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -75,10 +75,6 @@ MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); | |||
75 | #define dprintk(level,fmt, arg...) if (video_debug >= level) \ | 75 | #define dprintk(level,fmt, arg...) if (video_debug >= level) \ |
76 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) | 76 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) |
77 | 77 | ||
78 | /* ------------------------------------------------------------------ */ | ||
79 | |||
80 | static LIST_HEAD(cx8800_devlist); | ||
81 | |||
82 | /* ------------------------------------------------------------------- */ | 78 | /* ------------------------------------------------------------------- */ |
83 | /* static data */ | 79 | /* static data */ |
84 | 80 | ||
@@ -753,38 +749,31 @@ static int get_ressource(struct cx8800_fh *fh) | |||
753 | 749 | ||
754 | static int video_open(struct file *file) | 750 | static int video_open(struct file *file) |
755 | { | 751 | { |
756 | int minor = video_devdata(file)->minor; | 752 | struct video_device *vdev = video_devdata(file); |
757 | struct cx8800_dev *h,*dev = NULL; | 753 | struct cx8800_dev *dev = video_drvdata(file); |
758 | struct cx88_core *core; | 754 | struct cx88_core *core; |
759 | struct cx8800_fh *fh; | 755 | struct cx8800_fh *fh; |
760 | enum v4l2_buf_type type = 0; | 756 | enum v4l2_buf_type type = 0; |
761 | int radio = 0; | 757 | int radio = 0; |
762 | 758 | ||
763 | lock_kernel(); | 759 | switch (vdev->vfl_type) { |
764 | list_for_each_entry(h, &cx8800_devlist, devlist) { | 760 | case VFL_TYPE_GRABBER: |
765 | if (h->video_dev->minor == minor) { | 761 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
766 | dev = h; | 762 | break; |
767 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 763 | case VFL_TYPE_VBI: |
768 | } | 764 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
769 | if (h->vbi_dev->minor == minor) { | 765 | break; |
770 | dev = h; | 766 | case VFL_TYPE_RADIO: |
771 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 767 | radio = 1; |
772 | } | 768 | break; |
773 | if (h->radio_dev && | ||
774 | h->radio_dev->minor == minor) { | ||
775 | radio = 1; | ||
776 | dev = h; | ||
777 | } | ||
778 | } | ||
779 | if (NULL == dev) { | ||
780 | unlock_kernel(); | ||
781 | return -ENODEV; | ||
782 | } | 769 | } |
783 | 770 | ||
771 | lock_kernel(); | ||
772 | |||
784 | core = dev->core; | 773 | core = dev->core; |
785 | 774 | ||
786 | dprintk(1,"open minor=%d radio=%d type=%s\n", | 775 | dprintk(1, "open dev=%s radio=%d type=%s\n", |
787 | minor,radio,v4l2_type_names[type]); | 776 | video_device_node_name(vdev), radio, v4l2_type_names[type]); |
788 | 777 | ||
789 | /* allocate + initialize per filehandle data */ | 778 | /* allocate + initialize per filehandle data */ |
790 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 779 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
@@ -1733,7 +1722,6 @@ static struct video_device cx8800_vbi_template; | |||
1733 | static struct video_device cx8800_video_template = { | 1722 | static struct video_device cx8800_video_template = { |
1734 | .name = "cx8800-video", | 1723 | .name = "cx8800-video", |
1735 | .fops = &video_fops, | 1724 | .fops = &video_fops, |
1736 | .minor = -1, | ||
1737 | .ioctl_ops = &video_ioctl_ops, | 1725 | .ioctl_ops = &video_ioctl_ops, |
1738 | .tvnorms = CX88_NORMS, | 1726 | .tvnorms = CX88_NORMS, |
1739 | .current_norm = V4L2_STD_NTSC_M, | 1727 | .current_norm = V4L2_STD_NTSC_M, |
@@ -1769,7 +1757,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { | |||
1769 | static struct video_device cx8800_radio_template = { | 1757 | static struct video_device cx8800_radio_template = { |
1770 | .name = "cx8800-radio", | 1758 | .name = "cx8800-radio", |
1771 | .fops = &radio_fops, | 1759 | .fops = &radio_fops, |
1772 | .minor = -1, | ||
1773 | .ioctl_ops = &radio_ioctl_ops, | 1760 | .ioctl_ops = &radio_ioctl_ops, |
1774 | }; | 1761 | }; |
1775 | 1762 | ||
@@ -1778,21 +1765,21 @@ static struct video_device cx8800_radio_template = { | |||
1778 | static void cx8800_unregister_video(struct cx8800_dev *dev) | 1765 | static void cx8800_unregister_video(struct cx8800_dev *dev) |
1779 | { | 1766 | { |
1780 | if (dev->radio_dev) { | 1767 | if (dev->radio_dev) { |
1781 | if (-1 != dev->radio_dev->minor) | 1768 | if (video_is_registered(dev->radio_dev)) |
1782 | video_unregister_device(dev->radio_dev); | 1769 | video_unregister_device(dev->radio_dev); |
1783 | else | 1770 | else |
1784 | video_device_release(dev->radio_dev); | 1771 | video_device_release(dev->radio_dev); |
1785 | dev->radio_dev = NULL; | 1772 | dev->radio_dev = NULL; |
1786 | } | 1773 | } |
1787 | if (dev->vbi_dev) { | 1774 | if (dev->vbi_dev) { |
1788 | if (-1 != dev->vbi_dev->minor) | 1775 | if (video_is_registered(dev->vbi_dev)) |
1789 | video_unregister_device(dev->vbi_dev); | 1776 | video_unregister_device(dev->vbi_dev); |
1790 | else | 1777 | else |
1791 | video_device_release(dev->vbi_dev); | 1778 | video_device_release(dev->vbi_dev); |
1792 | dev->vbi_dev = NULL; | 1779 | dev->vbi_dev = NULL; |
1793 | } | 1780 | } |
1794 | if (dev->video_dev) { | 1781 | if (dev->video_dev) { |
1795 | if (-1 != dev->video_dev->minor) | 1782 | if (video_is_registered(dev->video_dev)) |
1796 | video_unregister_device(dev->video_dev); | 1783 | video_unregister_device(dev->video_dev); |
1797 | else | 1784 | else |
1798 | video_device_release(dev->video_dev); | 1785 | video_device_release(dev->video_dev); |
@@ -1909,6 +1896,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1909 | /* register v4l devices */ | 1896 | /* register v4l devices */ |
1910 | dev->video_dev = cx88_vdev_init(core,dev->pci, | 1897 | dev->video_dev = cx88_vdev_init(core,dev->pci, |
1911 | &cx8800_video_template,"video"); | 1898 | &cx8800_video_template,"video"); |
1899 | video_set_drvdata(dev->video_dev, dev); | ||
1912 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | 1900 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, |
1913 | video_nr[core->nr]); | 1901 | video_nr[core->nr]); |
1914 | if (err < 0) { | 1902 | if (err < 0) { |
@@ -1916,10 +1904,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1916 | core->name); | 1904 | core->name); |
1917 | goto fail_unreg; | 1905 | goto fail_unreg; |
1918 | } | 1906 | } |
1919 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", | 1907 | printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", |
1920 | core->name, dev->video_dev->num); | 1908 | core->name, video_device_node_name(dev->video_dev)); |
1921 | 1909 | ||
1922 | dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); | 1910 | dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); |
1911 | video_set_drvdata(dev->vbi_dev, dev); | ||
1923 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | 1912 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, |
1924 | vbi_nr[core->nr]); | 1913 | vbi_nr[core->nr]); |
1925 | if (err < 0) { | 1914 | if (err < 0) { |
@@ -1927,12 +1916,13 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1927 | core->name); | 1916 | core->name); |
1928 | goto fail_unreg; | 1917 | goto fail_unreg; |
1929 | } | 1918 | } |
1930 | printk(KERN_INFO "%s/0: registered device vbi%d\n", | 1919 | printk(KERN_INFO "%s/0: registered device %s\n", |
1931 | core->name, dev->vbi_dev->num); | 1920 | core->name, video_device_node_name(dev->vbi_dev)); |
1932 | 1921 | ||
1933 | if (core->board.radio.type == CX88_RADIO) { | 1922 | if (core->board.radio.type == CX88_RADIO) { |
1934 | dev->radio_dev = cx88_vdev_init(core,dev->pci, | 1923 | dev->radio_dev = cx88_vdev_init(core,dev->pci, |
1935 | &cx8800_radio_template,"radio"); | 1924 | &cx8800_radio_template,"radio"); |
1925 | video_set_drvdata(dev->radio_dev, dev); | ||
1936 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | 1926 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
1937 | radio_nr[core->nr]); | 1927 | radio_nr[core->nr]); |
1938 | if (err < 0) { | 1928 | if (err < 0) { |
@@ -1940,12 +1930,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1940 | core->name); | 1930 | core->name); |
1941 | goto fail_unreg; | 1931 | goto fail_unreg; |
1942 | } | 1932 | } |
1943 | printk(KERN_INFO "%s/0: registered device radio%d\n", | 1933 | printk(KERN_INFO "%s/0: registered device %s\n", |
1944 | core->name, dev->radio_dev->num); | 1934 | core->name, video_device_node_name(dev->radio_dev)); |
1945 | } | 1935 | } |
1946 | 1936 | ||
1947 | /* everything worked */ | 1937 | /* everything worked */ |
1948 | list_add_tail(&dev->devlist,&cx8800_devlist); | ||
1949 | pci_set_drvdata(pci_dev,dev); | 1938 | pci_set_drvdata(pci_dev,dev); |
1950 | 1939 | ||
1951 | /* initial device configuration */ | 1940 | /* initial device configuration */ |
@@ -2001,7 +1990,6 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev) | |||
2001 | 1990 | ||
2002 | /* free memory */ | 1991 | /* free memory */ |
2003 | btcx_riscmem_free(dev->pci,&dev->vidq.stopper); | 1992 | btcx_riscmem_free(dev->pci,&dev->vidq.stopper); |
2004 | list_del(&dev->devlist); | ||
2005 | cx88_core_put(core,dev->pci); | 1993 | cx88_core_put(core,dev->pci); |
2006 | kfree(dev); | 1994 | kfree(dev); |
2007 | } | 1995 | } |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e1c521710103..b1499bf604ea 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -423,7 +423,6 @@ struct cx8800_suspend_state { | |||
423 | 423 | ||
424 | struct cx8800_dev { | 424 | struct cx8800_dev { |
425 | struct cx88_core *core; | 425 | struct cx88_core *core; |
426 | struct list_head devlist; | ||
427 | spinlock_t slock; | 426 | spinlock_t slock; |
428 | 427 | ||
429 | /* various device info */ | 428 | /* various device info */ |
@@ -670,7 +669,6 @@ int cx88_audio_thread(void *data); | |||
670 | 669 | ||
671 | int cx8802_register_driver(struct cx8802_driver *drv); | 670 | int cx8802_register_driver(struct cx8802_driver *drv); |
672 | int cx8802_unregister_driver(struct cx8802_driver *drv); | 671 | int cx8802_unregister_driver(struct cx8802_driver *drv); |
673 | struct cx8802_dev *cx8802_get_device(int minor); | ||
674 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); | 672 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); |
675 | 673 | ||
676 | /* ----------------------------------------------------------- */ | 674 | /* ----------------------------------------------------------- */ |
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index c3916a42668e..de22bc9faf21 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c | |||
@@ -70,7 +70,6 @@ | |||
70 | #include <linux/init.h> | 70 | #include <linux/init.h> |
71 | #include <linux/platform_device.h> | 71 | #include <linux/platform_device.h> |
72 | #include <linux/interrupt.h> | 72 | #include <linux/interrupt.h> |
73 | #include <linux/version.h> | ||
74 | #include <media/v4l2-common.h> | 73 | #include <media/v4l2-common.h> |
75 | #include <linux/io.h> | 74 | #include <linux/io.h> |
76 | #include <media/davinci/vpfe_capture.h> | 75 | #include <media/davinci/vpfe_capture.h> |
@@ -1967,7 +1966,6 @@ static __init int vpfe_probe(struct platform_device *pdev) | |||
1967 | vfd->release = video_device_release; | 1966 | vfd->release = video_device_release; |
1968 | vfd->fops = &vpfe_fops; | 1967 | vfd->fops = &vpfe_fops; |
1969 | vfd->ioctl_ops = &vpfe_ioctl_ops; | 1968 | vfd->ioctl_ops = &vpfe_ioctl_ops; |
1970 | vfd->minor = -1; | ||
1971 | vfd->tvnorms = 0; | 1969 | vfd->tvnorms = 0; |
1972 | vfd->current_norm = V4L2_STD_PAL; | 1970 | vfd->current_norm = V4L2_STD_PAL; |
1973 | vfd->v4l2_dev = &vpfe_dev->v4l2_dev; | 1971 | vfd->v4l2_dev = &vpfe_dev->v4l2_dev; |
@@ -2071,7 +2069,7 @@ probe_out_video_unregister: | |||
2071 | probe_out_v4l2_unregister: | 2069 | probe_out_v4l2_unregister: |
2072 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | 2070 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); |
2073 | probe_out_video_release: | 2071 | probe_out_video_release: |
2074 | if (vpfe_dev->video_dev->minor == -1) | 2072 | if (!video_is_registered(vpfe_dev->video_dev)) |
2075 | video_device_release(vpfe_dev->video_dev); | 2073 | video_device_release(vpfe_dev->video_dev); |
2076 | probe_out_release_irq: | 2074 | probe_out_release_irq: |
2077 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | 2075 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); |
@@ -2091,7 +2089,7 @@ probe_free_dev_mem: | |||
2091 | /* | 2089 | /* |
2092 | * vpfe_remove : It un-register device from V4L2 driver | 2090 | * vpfe_remove : It un-register device from V4L2 driver |
2093 | */ | 2091 | */ |
2094 | static int vpfe_remove(struct platform_device *pdev) | 2092 | static int __devexit vpfe_remove(struct platform_device *pdev) |
2095 | { | 2093 | { |
2096 | struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); | 2094 | struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); |
2097 | struct resource *res; | 2095 | struct resource *res; |
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 3b8eac31ecae..1f532e31cd49 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c | |||
@@ -266,7 +266,7 @@ fail: | |||
266 | return status; | 266 | return status; |
267 | } | 267 | } |
268 | 268 | ||
269 | static int vpif_remove(struct platform_device *pdev) | 269 | static int __devexit vpif_remove(struct platform_device *pdev) |
270 | { | 270 | { |
271 | iounmap(vpif_base); | 271 | iounmap(vpif_base); |
272 | release_mem_region(res->start, res_len); | 272 | release_mem_region(res->start, res_len); |
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index d14cfb200ed0..dfddef7228dd 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c | |||
@@ -1347,7 +1347,6 @@ static const struct v4l2_file_operations vpif_fops = { | |||
1347 | static struct video_device vpif_video_template = { | 1347 | static struct video_device vpif_video_template = { |
1348 | .name = "vpif", | 1348 | .name = "vpif", |
1349 | .fops = &vpif_fops, | 1349 | .fops = &vpif_fops, |
1350 | .minor = -1, | ||
1351 | .ioctl_ops = &vpif_ioctl_ops, | 1350 | .ioctl_ops = &vpif_ioctl_ops, |
1352 | .tvnorms = DM646X_V4L2_STD, | 1351 | .tvnorms = DM646X_V4L2_STD, |
1353 | .current_norm = V4L2_STD_625_50, | 1352 | .current_norm = V4L2_STD_625_50, |
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 453236bd7559..7ee72ecd3d81 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c | |||
@@ -268,7 +268,7 @@ fail1: | |||
268 | return status; | 268 | return status; |
269 | } | 269 | } |
270 | 270 | ||
271 | static int vpss_remove(struct platform_device *pdev) | 271 | static int __devexit vpss_remove(struct platform_device *pdev) |
272 | { | 272 | { |
273 | iounmap(oper_cfg.vpss_bl_regs_base); | 273 | iounmap(oper_cfg.vpss_bl_regs_base); |
274 | release_mem_region(oper_cfg.r1->start, oper_cfg.len1); | 274 | release_mem_region(oper_cfg.r1->start, oper_cfg.len1); |
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 82da205047be..25100001ffff 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -2285,7 +2285,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev) | |||
2285 | dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; | 2285 | dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; |
2286 | break; | 2286 | break; |
2287 | case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: | 2287 | case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: |
2288 | dev->init_data.ir_codes = &ir_codes_hauppauge_new_table; | 2288 | dev->init_data.ir_codes = &ir_codes_rc5_hauppauge_new_table; |
2289 | dev->init_data.get_key = em28xx_get_key_em_haup; | 2289 | dev->init_data.get_key = em28xx_get_key_em_haup; |
2290 | dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; | 2290 | dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; |
2291 | break; | 2291 | break; |
@@ -2653,7 +2653,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2653 | INIT_LIST_HEAD(&dev->vbiq.active); | 2653 | INIT_LIST_HEAD(&dev->vbiq.active); |
2654 | INIT_LIST_HEAD(&dev->vbiq.queued); | 2654 | INIT_LIST_HEAD(&dev->vbiq.queued); |
2655 | 2655 | ||
2656 | |||
2657 | if (dev->board.has_msp34xx) { | 2656 | if (dev->board.has_msp34xx) { |
2658 | /* Send a reset to other chips via gpio */ | 2657 | /* Send a reset to other chips via gpio */ |
2659 | errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); | 2658 | errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); |
@@ -2923,9 +2922,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
2923 | 2922 | ||
2924 | if (dev->users) { | 2923 | if (dev->users) { |
2925 | em28xx_warn | 2924 | em28xx_warn |
2926 | ("device /dev/video%d is open! Deregistration and memory " | 2925 | ("device %s is open! Deregistration and memory " |
2927 | "deallocation are deferred on close.\n", | 2926 | "deallocation are deferred on close.\n", |
2928 | dev->vdev->num); | 2927 | video_device_node_name(dev->vdev)); |
2929 | 2928 | ||
2930 | dev->state |= DEV_MISCONFIGURED; | 2929 | dev->state |= DEV_MISCONFIGURED; |
2931 | em28xx_uninit_isoc(dev); | 2930 | em28xx_uninit_isoc(dev); |
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 3f86d36dff2b..b311d4514bdf 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
@@ -216,7 +216,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) | |||
216 | * sets only some bits (specified by bitmask) of a register, by first reading | 216 | * sets only some bits (specified by bitmask) of a register, by first reading |
217 | * the actual value | 217 | * the actual value |
218 | */ | 218 | */ |
219 | static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, | 219 | int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, |
220 | u8 bitmask) | 220 | u8 bitmask) |
221 | { | 221 | { |
222 | int oldval; | 222 | int oldval; |
@@ -1136,34 +1136,6 @@ void em28xx_wake_i2c(struct em28xx *dev) | |||
1136 | static LIST_HEAD(em28xx_devlist); | 1136 | static LIST_HEAD(em28xx_devlist); |
1137 | static DEFINE_MUTEX(em28xx_devlist_mutex); | 1137 | static DEFINE_MUTEX(em28xx_devlist_mutex); |
1138 | 1138 | ||
1139 | struct em28xx *em28xx_get_device(int minor, | ||
1140 | enum v4l2_buf_type *fh_type, | ||
1141 | int *has_radio) | ||
1142 | { | ||
1143 | struct em28xx *h, *dev = NULL; | ||
1144 | |||
1145 | *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1146 | *has_radio = 0; | ||
1147 | |||
1148 | mutex_lock(&em28xx_devlist_mutex); | ||
1149 | list_for_each_entry(h, &em28xx_devlist, devlist) { | ||
1150 | if (h->vdev->minor == minor) | ||
1151 | dev = h; | ||
1152 | if (h->vbi_dev && h->vbi_dev->minor == minor) { | ||
1153 | dev = h; | ||
1154 | *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
1155 | } | ||
1156 | if (h->radio_dev && | ||
1157 | h->radio_dev->minor == minor) { | ||
1158 | dev = h; | ||
1159 | *has_radio = 1; | ||
1160 | } | ||
1161 | } | ||
1162 | mutex_unlock(&em28xx_devlist_mutex); | ||
1163 | |||
1164 | return dev; | ||
1165 | } | ||
1166 | |||
1167 | /* | 1139 | /* |
1168 | * em28xx_realease_resources() | 1140 | * em28xx_realease_resources() |
1169 | * unregisters the v4l2,i2c and usb devices | 1141 | * unregisters the v4l2,i2c and usb devices |
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index d96ec7c09dca..af0d935c29be 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c | |||
@@ -112,10 +112,13 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
112 | int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | 112 | int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) |
113 | { | 113 | { |
114 | unsigned char buf[2]; | 114 | unsigned char buf[2]; |
115 | unsigned char code; | 115 | u16 code; |
116 | int size; | ||
116 | 117 | ||
117 | /* poll IR chip */ | 118 | /* poll IR chip */ |
118 | if (2 != i2c_master_recv(ir->c, buf, 2)) | 119 | size = i2c_master_recv(ir->c, buf, sizeof(buf)); |
120 | |||
121 | if (size != 2) | ||
119 | return -EIO; | 122 | return -EIO; |
120 | 123 | ||
121 | /* Does eliminate repeated parity code */ | 124 | /* Does eliminate repeated parity code */ |
@@ -124,16 +127,30 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
124 | 127 | ||
125 | ir->old = buf[1]; | 128 | ir->old = buf[1]; |
126 | 129 | ||
127 | /* Rearranges bits to the right order */ | 130 | /* |
128 | code = ((buf[0]&0x01)<<5) | /* 0010 0000 */ | 131 | * Rearranges bits to the right order. |
129 | ((buf[0]&0x02)<<3) | /* 0001 0000 */ | 132 | * The bit order were determined experimentally by using |
130 | ((buf[0]&0x04)<<1) | /* 0000 1000 */ | 133 | * The original Hauppauge Grey IR and another RC5 that uses addr=0x08 |
131 | ((buf[0]&0x08)>>1) | /* 0000 0100 */ | 134 | * The RC5 code has 14 bits, but we've experimentally determined |
132 | ((buf[0]&0x10)>>3) | /* 0000 0010 */ | 135 | * the meaning for only 11 bits. |
133 | ((buf[0]&0x20)>>5); /* 0000 0001 */ | 136 | * So, the code translation is not complete. Yet, it is enough to |
134 | 137 | * work with the provided RC5 IR. | |
135 | i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", | 138 | */ |
136 | code, buf[0]); | 139 | code = |
140 | ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */ | ||
141 | ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */ | ||
142 | ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */ | ||
143 | ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */ | ||
144 | ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */ | ||
145 | ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */ | ||
146 | ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */ | ||
147 | ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */ | ||
148 | ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */ | ||
149 | ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */ | ||
150 | ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */ | ||
151 | |||
152 | i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n", | ||
153 | code, buf[1], buf[0]); | ||
137 | 154 | ||
138 | /* return key */ | 155 | /* return key */ |
139 | *ir_key = code; | 156 | *ir_key = code; |
@@ -337,19 +354,28 @@ int em28xx_ir_init(struct em28xx *dev) | |||
337 | goto err_out_free; | 354 | goto err_out_free; |
338 | 355 | ||
339 | ir->input = input_dev; | 356 | ir->input = input_dev; |
357 | ir_config = EM2874_IR_RC5; | ||
358 | |||
359 | /* Adjust xclk based o IR table for RC5/NEC tables */ | ||
360 | if (dev->board.ir_codes->ir_type == IR_TYPE_RC5) { | ||
361 | dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; | ||
362 | ir->full_code = 1; | ||
363 | } else if (dev->board.ir_codes->ir_type == IR_TYPE_NEC) { | ||
364 | dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; | ||
365 | ir_config = EM2874_IR_NEC; | ||
366 | ir->full_code = 1; | ||
367 | } | ||
368 | em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, | ||
369 | EM28XX_XCLK_IR_RC5_MODE); | ||
340 | 370 | ||
341 | /* Setup the proper handler based on the chip */ | 371 | /* Setup the proper handler based on the chip */ |
342 | switch (dev->chip_id) { | 372 | switch (dev->chip_id) { |
343 | case CHIP_ID_EM2860: | 373 | case CHIP_ID_EM2860: |
344 | case CHIP_ID_EM2883: | 374 | case CHIP_ID_EM2883: |
345 | if (dev->model == EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950) | ||
346 | ir->full_code = 1; | ||
347 | ir->get_key = default_polling_getkey; | 375 | ir->get_key = default_polling_getkey; |
348 | break; | 376 | break; |
349 | case CHIP_ID_EM2874: | 377 | case CHIP_ID_EM2874: |
350 | ir->get_key = em2874_polling_getkey; | 378 | ir->get_key = em2874_polling_getkey; |
351 | /* For now we only support RC5, so enable it */ | ||
352 | ir_config = EM2874_IR_RC5; | ||
353 | em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); | 379 | em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); |
354 | break; | 380 | break; |
355 | default: | 381 | default: |
@@ -367,8 +393,7 @@ int em28xx_ir_init(struct em28xx *dev) | |||
367 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); | 393 | usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); |
368 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); | 394 | strlcat(ir->phys, "/input0", sizeof(ir->phys)); |
369 | 395 | ||
370 | err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, | 396 | err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); |
371 | dev->board.ir_codes); | ||
372 | if (err < 0) | 397 | if (err < 0) |
373 | goto err_out_free; | 398 | goto err_out_free; |
374 | 399 | ||
@@ -387,7 +412,7 @@ int em28xx_ir_init(struct em28xx *dev) | |||
387 | em28xx_ir_start(ir); | 412 | em28xx_ir_start(ir); |
388 | 413 | ||
389 | /* all done */ | 414 | /* all done */ |
390 | err = input_register_device(ir->input); | 415 | err = ir_input_register(ir->input, dev->board.ir_codes); |
391 | if (err) | 416 | if (err) |
392 | goto err_out_stop; | 417 | goto err_out_stop; |
393 | 418 | ||
@@ -396,8 +421,6 @@ int em28xx_ir_init(struct em28xx *dev) | |||
396 | em28xx_ir_stop(ir); | 421 | em28xx_ir_stop(ir); |
397 | dev->ir = NULL; | 422 | dev->ir = NULL; |
398 | err_out_free: | 423 | err_out_free: |
399 | ir_input_free(input_dev); | ||
400 | input_free_device(input_dev); | ||
401 | kfree(ir); | 424 | kfree(ir); |
402 | return err; | 425 | return err; |
403 | } | 426 | } |
@@ -411,8 +434,7 @@ int em28xx_ir_fini(struct em28xx *dev) | |||
411 | return 0; | 434 | return 0; |
412 | 435 | ||
413 | em28xx_ir_stop(ir); | 436 | em28xx_ir_stop(ir); |
414 | ir_input_free(ir->input); | 437 | ir_input_unregister(ir->input); |
415 | input_unregister_device(ir->input); | ||
416 | kfree(ir); | 438 | kfree(ir); |
417 | 439 | ||
418 | /* done */ | 440 | /* done */ |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 7ad65370f274..849b18c94037 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -2081,22 +2081,30 @@ static int radio_queryctrl(struct file *file, void *priv, | |||
2081 | */ | 2081 | */ |
2082 | static int em28xx_v4l2_open(struct file *filp) | 2082 | static int em28xx_v4l2_open(struct file *filp) |
2083 | { | 2083 | { |
2084 | int minor = video_devdata(filp)->minor; | 2084 | int errCode = 0, radio = 0; |
2085 | int errCode = 0, radio; | 2085 | struct video_device *vdev = video_devdata(filp); |
2086 | struct em28xx *dev; | 2086 | struct em28xx *dev = video_drvdata(filp); |
2087 | enum v4l2_buf_type fh_type; | 2087 | enum v4l2_buf_type fh_type = 0; |
2088 | struct em28xx_fh *fh; | 2088 | struct em28xx_fh *fh; |
2089 | enum v4l2_field field; | 2089 | enum v4l2_field field; |
2090 | 2090 | ||
2091 | dev = em28xx_get_device(minor, &fh_type, &radio); | 2091 | switch (vdev->vfl_type) { |
2092 | 2092 | case VFL_TYPE_GRABBER: | |
2093 | if (NULL == dev) | 2093 | fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
2094 | return -ENODEV; | 2094 | break; |
2095 | case VFL_TYPE_VBI: | ||
2096 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
2097 | break; | ||
2098 | case VFL_TYPE_RADIO: | ||
2099 | radio = 1; | ||
2100 | break; | ||
2101 | } | ||
2095 | 2102 | ||
2096 | mutex_lock(&dev->lock); | 2103 | mutex_lock(&dev->lock); |
2097 | 2104 | ||
2098 | em28xx_videodbg("open minor=%d type=%s users=%d\n", | 2105 | em28xx_videodbg("open dev=%s type=%s users=%d\n", |
2099 | minor, v4l2_type_names[fh_type], dev->users); | 2106 | video_device_node_name(vdev), v4l2_type_names[fh_type], |
2107 | dev->users); | ||
2100 | 2108 | ||
2101 | 2109 | ||
2102 | fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); | 2110 | fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); |
@@ -2160,25 +2168,25 @@ void em28xx_release_analog_resources(struct em28xx *dev) | |||
2160 | /*FIXME: I2C IR should be disconnected */ | 2168 | /*FIXME: I2C IR should be disconnected */ |
2161 | 2169 | ||
2162 | if (dev->radio_dev) { | 2170 | if (dev->radio_dev) { |
2163 | if (-1 != dev->radio_dev->minor) | 2171 | if (video_is_registered(dev->radio_dev)) |
2164 | video_unregister_device(dev->radio_dev); | 2172 | video_unregister_device(dev->radio_dev); |
2165 | else | 2173 | else |
2166 | video_device_release(dev->radio_dev); | 2174 | video_device_release(dev->radio_dev); |
2167 | dev->radio_dev = NULL; | 2175 | dev->radio_dev = NULL; |
2168 | } | 2176 | } |
2169 | if (dev->vbi_dev) { | 2177 | if (dev->vbi_dev) { |
2170 | em28xx_info("V4L2 device /dev/vbi%d deregistered\n", | 2178 | em28xx_info("V4L2 device %s deregistered\n", |
2171 | dev->vbi_dev->num); | 2179 | video_device_node_name(dev->vbi_dev)); |
2172 | if (-1 != dev->vbi_dev->minor) | 2180 | if (video_is_registered(dev->vbi_dev)) |
2173 | video_unregister_device(dev->vbi_dev); | 2181 | video_unregister_device(dev->vbi_dev); |
2174 | else | 2182 | else |
2175 | video_device_release(dev->vbi_dev); | 2183 | video_device_release(dev->vbi_dev); |
2176 | dev->vbi_dev = NULL; | 2184 | dev->vbi_dev = NULL; |
2177 | } | 2185 | } |
2178 | if (dev->vdev) { | 2186 | if (dev->vdev) { |
2179 | em28xx_info("V4L2 device /dev/video%d deregistered\n", | 2187 | em28xx_info("V4L2 device %s deregistered\n", |
2180 | dev->vdev->num); | 2188 | video_device_node_name(dev->vdev)); |
2181 | if (-1 != dev->vdev->minor) | 2189 | if (video_is_registered(dev->vdev)) |
2182 | video_unregister_device(dev->vdev); | 2190 | video_unregister_device(dev->vdev); |
2183 | else | 2191 | else |
2184 | video_device_release(dev->vdev); | 2192 | video_device_release(dev->vdev); |
@@ -2397,8 +2405,6 @@ static const struct video_device em28xx_video_template = { | |||
2397 | .release = video_device_release, | 2405 | .release = video_device_release, |
2398 | .ioctl_ops = &video_ioctl_ops, | 2406 | .ioctl_ops = &video_ioctl_ops, |
2399 | 2407 | ||
2400 | .minor = -1, | ||
2401 | |||
2402 | .tvnorms = V4L2_STD_ALL, | 2408 | .tvnorms = V4L2_STD_ALL, |
2403 | .current_norm = V4L2_STD_PAL, | 2409 | .current_norm = V4L2_STD_PAL, |
2404 | }; | 2410 | }; |
@@ -2433,7 +2439,6 @@ static struct video_device em28xx_radio_template = { | |||
2433 | .name = "em28xx-radio", | 2439 | .name = "em28xx-radio", |
2434 | .fops = &radio_fops, | 2440 | .fops = &radio_fops, |
2435 | .ioctl_ops = &radio_ioctl_ops, | 2441 | .ioctl_ops = &radio_ioctl_ops, |
2436 | .minor = -1, | ||
2437 | }; | 2442 | }; |
2438 | 2443 | ||
2439 | /******************************** usb interface ******************************/ | 2444 | /******************************** usb interface ******************************/ |
@@ -2451,7 +2456,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
2451 | return NULL; | 2456 | return NULL; |
2452 | 2457 | ||
2453 | *vfd = *template; | 2458 | *vfd = *template; |
2454 | vfd->minor = -1; | ||
2455 | vfd->v4l2_dev = &dev->v4l2_dev; | 2459 | vfd->v4l2_dev = &dev->v4l2_dev; |
2456 | vfd->release = video_device_release; | 2460 | vfd->release = video_device_release; |
2457 | vfd->debug = video_debug; | 2461 | vfd->debug = video_debug; |
@@ -2459,6 +2463,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
2459 | snprintf(vfd->name, sizeof(vfd->name), "%s %s", | 2463 | snprintf(vfd->name, sizeof(vfd->name), "%s %s", |
2460 | dev->name, type_name); | 2464 | dev->name, type_name); |
2461 | 2465 | ||
2466 | video_set_drvdata(vfd, dev); | ||
2462 | return vfd; | 2467 | return vfd; |
2463 | } | 2468 | } |
2464 | 2469 | ||
@@ -2540,16 +2545,16 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
2540 | em28xx_errdev("can't register radio device\n"); | 2545 | em28xx_errdev("can't register radio device\n"); |
2541 | return ret; | 2546 | return ret; |
2542 | } | 2547 | } |
2543 | em28xx_info("Registered radio device as /dev/radio%d\n", | 2548 | em28xx_info("Registered radio device as %s\n", |
2544 | dev->radio_dev->num); | 2549 | video_device_node_name(dev->radio_dev)); |
2545 | } | 2550 | } |
2546 | 2551 | ||
2547 | em28xx_info("V4L2 video device registered as /dev/video%d\n", | 2552 | em28xx_info("V4L2 video device registered as %s\n", |
2548 | dev->vdev->num); | 2553 | video_device_node_name(dev->vdev)); |
2549 | 2554 | ||
2550 | if (dev->vbi_dev) | 2555 | if (dev->vbi_dev) |
2551 | em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n", | 2556 | em28xx_info("V4L2 VBI device registered as %s\n", |
2552 | dev->vbi_dev->num); | 2557 | video_device_node_name(dev->vbi_dev)); |
2553 | 2558 | ||
2554 | return 0; | 2559 | return 0; |
2555 | } | 2560 | } |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 441df644ddbe..80d9b4fa1b97 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -643,6 +643,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, | |||
643 | int len); | 643 | int len); |
644 | int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); | 644 | int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); |
645 | int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); | 645 | int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); |
646 | int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, | ||
647 | u8 bitmask); | ||
646 | 648 | ||
647 | int em28xx_read_ac97(struct em28xx *dev, u8 reg); | 649 | int em28xx_read_ac97(struct em28xx *dev, u8 reg); |
648 | int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); | 650 | int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); |
@@ -666,9 +668,6 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); | |||
666 | void em28xx_wake_i2c(struct em28xx *dev); | 668 | void em28xx_wake_i2c(struct em28xx *dev); |
667 | void em28xx_remove_from_devlist(struct em28xx *dev); | 669 | void em28xx_remove_from_devlist(struct em28xx *dev); |
668 | void em28xx_add_into_devlist(struct em28xx *dev); | 670 | void em28xx_add_into_devlist(struct em28xx *dev); |
669 | struct em28xx *em28xx_get_device(int minor, | ||
670 | enum v4l2_buf_type *fh_type, | ||
671 | int *has_radio); | ||
672 | int em28xx_register_extension(struct em28xx_ops *dev); | 671 | int em28xx_register_extension(struct em28xx_ops *dev); |
673 | void em28xx_unregister_extension(struct em28xx_ops *dev); | 672 | void em28xx_unregister_extension(struct em28xx_ops *dev); |
674 | void em28xx_init_extension(struct em28xx *dev); | 673 | void em28xx_init_extension(struct em28xx *dev); |
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 88987a57cf7b..e6c23d509862 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c | |||
@@ -587,8 +587,8 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) | |||
587 | else if (cam->stream != STREAM_OFF) { | 587 | else if (cam->stream != STREAM_OFF) { |
588 | cam->state |= DEV_MISCONFIGURED; | 588 | cam->state |= DEV_MISCONFIGURED; |
589 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | 589 | DBG(1, "URB timeout reached. The camera is misconfigured. To " |
590 | "use it, close and open /dev/video%d again.", | 590 | "use it, close and open %s again.", |
591 | cam->v4ldev->num); | 591 | video_device_node_name(cam->v4ldev)); |
592 | return -EIO; | 592 | return -EIO; |
593 | } | 593 | } |
594 | 594 | ||
@@ -1195,7 +1195,8 @@ static void et61x251_release_resources(struct kref *kref) | |||
1195 | 1195 | ||
1196 | cam = container_of(kref, struct et61x251_device, kref); | 1196 | cam = container_of(kref, struct et61x251_device, kref); |
1197 | 1197 | ||
1198 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); | 1198 | DBG(2, "V4L2 device %s deregistered", |
1199 | video_device_node_name(cam->v4ldev)); | ||
1199 | video_set_drvdata(cam->v4ldev, NULL); | 1200 | video_set_drvdata(cam->v4ldev, NULL); |
1200 | video_unregister_device(cam->v4ldev); | 1201 | video_unregister_device(cam->v4ldev); |
1201 | usb_put_dev(cam->usbdev); | 1202 | usb_put_dev(cam->usbdev); |
@@ -1236,8 +1237,8 @@ static int et61x251_open(struct file *filp) | |||
1236 | } | 1237 | } |
1237 | 1238 | ||
1238 | if (cam->users) { | 1239 | if (cam->users) { |
1239 | DBG(2, "Device /dev/video%d is already in use", | 1240 | DBG(2, "Device %s is already in use", |
1240 | cam->v4ldev->num); | 1241 | video_device_node_name(cam->v4ldev)); |
1241 | DBG(3, "Simultaneous opens are not supported"); | 1242 | DBG(3, "Simultaneous opens are not supported"); |
1242 | if ((filp->f_flags & O_NONBLOCK) || | 1243 | if ((filp->f_flags & O_NONBLOCK) || |
1243 | (filp->f_flags & O_NDELAY)) { | 1244 | (filp->f_flags & O_NDELAY)) { |
@@ -1280,7 +1281,8 @@ static int et61x251_open(struct file *filp) | |||
1280 | cam->frame_count = 0; | 1281 | cam->frame_count = 0; |
1281 | et61x251_empty_framequeues(cam); | 1282 | et61x251_empty_framequeues(cam); |
1282 | 1283 | ||
1283 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); | 1284 | DBG(3, "Video device %s is open", |
1285 | video_device_node_name(cam->v4ldev)); | ||
1284 | 1286 | ||
1285 | out: | 1287 | out: |
1286 | mutex_unlock(&cam->open_mutex); | 1288 | mutex_unlock(&cam->open_mutex); |
@@ -1304,7 +1306,8 @@ static int et61x251_release(struct file *filp) | |||
1304 | cam->users--; | 1306 | cam->users--; |
1305 | wake_up_interruptible_nr(&cam->wait_open, 1); | 1307 | wake_up_interruptible_nr(&cam->wait_open, 1); |
1306 | 1308 | ||
1307 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); | 1309 | DBG(3, "Video device %s closed", |
1310 | video_device_node_name(cam->v4ldev)); | ||
1308 | 1311 | ||
1309 | kref_put(&cam->kref, et61x251_release_resources); | 1312 | kref_put(&cam->kref, et61x251_release_resources); |
1310 | 1313 | ||
@@ -1846,8 +1849,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) | |||
1846 | if (err) { /* atomic, no rollback in ioctl() */ | 1849 | if (err) { /* atomic, no rollback in ioctl() */ |
1847 | cam->state |= DEV_MISCONFIGURED; | 1850 | cam->state |= DEV_MISCONFIGURED; |
1848 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | 1851 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " |
1849 | "use the camera, close and open /dev/video%d again.", | 1852 | "use the camera, close and open %s again.", |
1850 | cam->v4ldev->num); | 1853 | video_device_node_name(cam->v4ldev)); |
1851 | return -EIO; | 1854 | return -EIO; |
1852 | } | 1855 | } |
1853 | 1856 | ||
@@ -1859,8 +1862,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) | |||
1859 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | 1862 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { |
1860 | cam->state |= DEV_MISCONFIGURED; | 1863 | cam->state |= DEV_MISCONFIGURED; |
1861 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | 1864 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " |
1862 | "use the camera, close and open /dev/video%d again.", | 1865 | "use the camera, close and open %s again.", |
1863 | cam->v4ldev->num); | 1866 | video_device_node_name(cam->v4ldev)); |
1864 | return -ENOMEM; | 1867 | return -ENOMEM; |
1865 | } | 1868 | } |
1866 | 1869 | ||
@@ -2069,8 +2072,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, | |||
2069 | if (err) { /* atomic, no rollback in ioctl() */ | 2072 | if (err) { /* atomic, no rollback in ioctl() */ |
2070 | cam->state |= DEV_MISCONFIGURED; | 2073 | cam->state |= DEV_MISCONFIGURED; |
2071 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | 2074 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " |
2072 | "use the camera, close and open /dev/video%d again.", | 2075 | "use the camera, close and open %s again.", |
2073 | cam->v4ldev->num); | 2076 | video_device_node_name(cam->v4ldev)); |
2074 | return -EIO; | 2077 | return -EIO; |
2075 | } | 2078 | } |
2076 | 2079 | ||
@@ -2081,8 +2084,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, | |||
2081 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | 2084 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { |
2082 | cam->state |= DEV_MISCONFIGURED; | 2085 | cam->state |= DEV_MISCONFIGURED; |
2083 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | 2086 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " |
2084 | "use the camera, close and open /dev/video%d again.", | 2087 | "use the camera, close and open %s again.", |
2085 | cam->v4ldev->num); | 2088 | video_device_node_name(cam->v4ldev)); |
2086 | return -ENOMEM; | 2089 | return -ENOMEM; |
2087 | } | 2090 | } |
2088 | 2091 | ||
@@ -2130,7 +2133,7 @@ et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) | |||
2130 | cam->state |= DEV_MISCONFIGURED; | 2133 | cam->state |= DEV_MISCONFIGURED; |
2131 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | 2134 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " |
2132 | "problems. To use the camera, close and open " | 2135 | "problems. To use the camera, close and open " |
2133 | "/dev/video%d again.", cam->v4ldev->num); | 2136 | "%s again.", video_device_node_name(cam->v4ldev)); |
2134 | return -EIO; | 2137 | return -EIO; |
2135 | } | 2138 | } |
2136 | 2139 | ||
@@ -2584,7 +2587,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2584 | 2587 | ||
2585 | strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); | 2588 | strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); |
2586 | cam->v4ldev->fops = &et61x251_fops; | 2589 | cam->v4ldev->fops = &et61x251_fops; |
2587 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
2588 | cam->v4ldev->release = video_device_release; | 2590 | cam->v4ldev->release = video_device_release; |
2589 | cam->v4ldev->parent = &udev->dev; | 2591 | cam->v4ldev->parent = &udev->dev; |
2590 | video_set_drvdata(cam->v4ldev, cam); | 2592 | video_set_drvdata(cam->v4ldev, cam); |
@@ -2603,7 +2605,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2603 | goto fail; | 2605 | goto fail; |
2604 | } | 2606 | } |
2605 | 2607 | ||
2606 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); | 2608 | DBG(2, "V4L2 device registered as %s", |
2609 | video_device_node_name(cam->v4ldev)); | ||
2607 | 2610 | ||
2608 | cam->module_param.force_munmap = force_munmap[dev_nr]; | 2611 | cam->module_param.force_munmap = force_munmap[dev_nr]; |
2609 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | 2612 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; |
@@ -2654,9 +2657,9 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) | |||
2654 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | 2657 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); |
2655 | 2658 | ||
2656 | if (cam->users) { | 2659 | if (cam->users) { |
2657 | DBG(2, "Device /dev/video%d is open! Deregistration and " | 2660 | DBG(2, "Device %s is open! Deregistration and memory " |
2658 | "memory deallocation are deferred.", | 2661 | "deallocation are deferred.", |
2659 | cam->v4ldev->num); | 2662 | video_device_node_name(cam->v4ldev)); |
2660 | cam->state |= DEV_MISCONFIGURED; | 2663 | cam->state |= DEV_MISCONFIGURED; |
2661 | et61x251_stop_transfer(cam); | 2664 | et61x251_stop_transfer(cam); |
2662 | cam->state |= DEV_DISCONNECTED; | 2665 | cam->state |= DEV_DISCONNECTED; |
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 2f0b8d621e00..c98b5d69c438 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c | |||
@@ -1046,14 +1046,14 @@ static struct sd_desc sd_desc = { | |||
1046 | }; | 1046 | }; |
1047 | 1047 | ||
1048 | /* -- module initialisation -- */ | 1048 | /* -- module initialisation -- */ |
1049 | static __devinitdata struct usb_device_id device_table[] = { | 1049 | static const struct usb_device_id device_table[] __devinitconst = { |
1050 | {USB_DEVICE(0x0572, 0x0041)}, | 1050 | {USB_DEVICE(0x0572, 0x0041)}, |
1051 | {} | 1051 | {} |
1052 | }; | 1052 | }; |
1053 | MODULE_DEVICE_TABLE(usb, device_table); | 1053 | MODULE_DEVICE_TABLE(usb, device_table); |
1054 | 1054 | ||
1055 | /* -- device connect -- */ | 1055 | /* -- device connect -- */ |
1056 | static int sd_probe(struct usb_interface *intf, | 1056 | static int __devinit sd_probe(struct usb_interface *intf, |
1057 | const struct usb_device_id *id) | 1057 | const struct usb_device_id *id) |
1058 | { | 1058 | { |
1059 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 1059 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 9de86419ae1e..fdf4c0ec5e7a 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c | |||
@@ -864,7 +864,7 @@ static struct sd_desc sd_desc = { | |||
864 | }; | 864 | }; |
865 | 865 | ||
866 | /* -- module initialisation -- */ | 866 | /* -- module initialisation -- */ |
867 | static __devinitdata struct usb_device_id device_table[] = { | 867 | static const struct usb_device_id device_table[] __devinitconst = { |
868 | {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, | 868 | {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, |
869 | #if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE | 869 | #if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE |
870 | {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, | 870 | {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, |
@@ -875,7 +875,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
875 | MODULE_DEVICE_TABLE(usb, device_table); | 875 | MODULE_DEVICE_TABLE(usb, device_table); |
876 | 876 | ||
877 | /* -- device connect -- */ | 877 | /* -- device connect -- */ |
878 | static int sd_probe(struct usb_interface *intf, | 878 | static int __devinit sd_probe(struct usb_interface *intf, |
879 | const struct usb_device_id *id) | 879 | const struct usb_device_id *id) |
880 | { | 880 | { |
881 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 881 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c index 1355e526ee84..c276a7debdec 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi1320.c +++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c | |||
@@ -345,7 +345,7 @@ static int mi1320_configure_alt(struct gspca_dev *gspca_dev) | |||
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
347 | 347 | ||
348 | int mi1320_camera_settings(struct gspca_dev *gspca_dev) | 348 | static int mi1320_camera_settings(struct gspca_dev *gspca_dev) |
349 | { | 349 | { |
350 | struct sd *sd = (struct sd *) gspca_dev; | 350 | struct sd *sd = (struct sd *) gspca_dev; |
351 | 351 | ||
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c index 80cb3f1b36f7..7c31b4f2abea 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi2020.c +++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c | |||
@@ -769,7 +769,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev) | |||
769 | return 0; | 769 | return 0; |
770 | } | 770 | } |
771 | 771 | ||
772 | int mi2020_camera_settings(struct gspca_dev *gspca_dev) | 772 | static int mi2020_camera_settings(struct gspca_dev *gspca_dev) |
773 | { | 773 | { |
774 | struct sd *sd = (struct sd *) gspca_dev; | 774 | struct sd *sd = (struct sd *) gspca_dev; |
775 | 775 | ||
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index a695e0ae13c2..4878c8f66543 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c | |||
@@ -40,7 +40,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
40 | static void sd_callback(struct gspca_dev *gspca_dev); | 40 | static void sd_callback(struct gspca_dev *gspca_dev); |
41 | 41 | ||
42 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, | 42 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, |
43 | s32 vendor_id, s32 product_id); | 43 | u16 vendor_id, u16 product_id); |
44 | 44 | ||
45 | /*============================ driver options ==============================*/ | 45 | /*============================ driver options ==============================*/ |
46 | 46 | ||
@@ -326,11 +326,11 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
326 | { | 326 | { |
327 | struct sd *sd = (struct sd *) gspca_dev; | 327 | struct sd *sd = (struct sd *) gspca_dev; |
328 | struct cam *cam; | 328 | struct cam *cam; |
329 | s32 vendor_id, product_id; | 329 | u16 vendor_id, product_id; |
330 | 330 | ||
331 | /* Get USB VendorID and ProductID */ | 331 | /* Get USB VendorID and ProductID */ |
332 | vendor_id = le16_to_cpu(id->idVendor); | 332 | vendor_id = id->idVendor; |
333 | product_id = le16_to_cpu(id->idProduct); | 333 | product_id = id->idProduct; |
334 | 334 | ||
335 | sd->nbRightUp = 1; | 335 | sd->nbRightUp = 1; |
336 | sd->nbIm = -1; | 336 | sd->nbIm = -1; |
@@ -534,8 +534,8 @@ static int sd_probe(struct usb_interface *intf, | |||
534 | gspca_dev = usb_get_intfdata(intf); | 534 | gspca_dev = usb_get_intfdata(intf); |
535 | 535 | ||
536 | PDEBUG(D_PROBE, | 536 | PDEBUG(D_PROBE, |
537 | "Camera is now controlling video device /dev/video%d", | 537 | "Camera is now controlling video device %s", |
538 | gspca_dev->vdev.minor); | 538 | video_device_node_name(&gspca_dev->vdev)); |
539 | } | 539 | } |
540 | 540 | ||
541 | return ret; | 541 | return ret; |
@@ -673,7 +673,7 @@ void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len) | |||
673 | } | 673 | } |
674 | 674 | ||
675 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, | 675 | static int gl860_guess_sensor(struct gspca_dev *gspca_dev, |
676 | s32 vendor_id, s32 product_id) | 676 | u16 vendor_id, u16 product_id) |
677 | { | 677 | { |
678 | struct sd *sd = (struct sd *) gspca_dev; | 678 | struct sd *sd = (struct sd *) gspca_dev; |
679 | u8 probe, nb26, nb96, nOV, ntry; | 679 | u8 probe, nb26, nb96, nOV, ntry; |
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 4076f8e5a6fc..e930a67d526b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -304,7 +304,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, | |||
304 | j = gspca_dev->fr_queue[i]; | 304 | j = gspca_dev->fr_queue[i]; |
305 | gspca_dev->cur_frame = &gspca_dev->frame[j]; | 305 | gspca_dev->cur_frame = &gspca_dev->frame[j]; |
306 | } | 306 | } |
307 | return; | ||
308 | } | 307 | } |
309 | EXPORT_SYMBOL(gspca_frame_add); | 308 | EXPORT_SYMBOL(gspca_frame_add); |
310 | 309 | ||
@@ -321,7 +320,7 @@ static int gspca_is_compressed(__u32 format) | |||
321 | return 0; | 320 | return 0; |
322 | } | 321 | } |
323 | 322 | ||
324 | static void *rvmalloc(unsigned long size) | 323 | static void *rvmalloc(long size) |
325 | { | 324 | { |
326 | void *mem; | 325 | void *mem; |
327 | unsigned long adr; | 326 | unsigned long adr; |
@@ -329,7 +328,7 @@ static void *rvmalloc(unsigned long size) | |||
329 | mem = vmalloc_32(size); | 328 | mem = vmalloc_32(size); |
330 | if (mem != NULL) { | 329 | if (mem != NULL) { |
331 | adr = (unsigned long) mem; | 330 | adr = (unsigned long) mem; |
332 | while ((long) size > 0) { | 331 | while (size > 0) { |
333 | SetPageReserved(vmalloc_to_page((void *) adr)); | 332 | SetPageReserved(vmalloc_to_page((void *) adr)); |
334 | adr += PAGE_SIZE; | 333 | adr += PAGE_SIZE; |
335 | size -= PAGE_SIZE; | 334 | size -= PAGE_SIZE; |
@@ -768,6 +767,7 @@ static int vidioc_g_register(struct file *file, void *priv, | |||
768 | 767 | ||
769 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 768 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
770 | return -ERESTARTSYS; | 769 | return -ERESTARTSYS; |
770 | gspca_dev->usb_err = 0; | ||
771 | if (gspca_dev->present) | 771 | if (gspca_dev->present) |
772 | ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); | 772 | ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); |
773 | else | 773 | else |
@@ -791,6 +791,7 @@ static int vidioc_s_register(struct file *file, void *priv, | |||
791 | 791 | ||
792 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 792 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
793 | return -ERESTARTSYS; | 793 | return -ERESTARTSYS; |
794 | gspca_dev->usb_err = 0; | ||
794 | if (gspca_dev->present) | 795 | if (gspca_dev->present) |
795 | ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); | 796 | ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); |
796 | else | 797 | else |
@@ -812,6 +813,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, | |||
812 | 813 | ||
813 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 814 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
814 | return -ERESTARTSYS; | 815 | return -ERESTARTSYS; |
816 | gspca_dev->usb_err = 0; | ||
815 | if (gspca_dev->present) | 817 | if (gspca_dev->present) |
816 | ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); | 818 | ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); |
817 | else | 819 | else |
@@ -983,11 +985,40 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, | |||
983 | return -EINVAL; | 985 | return -EINVAL; |
984 | } | 986 | } |
985 | 987 | ||
988 | static int vidioc_enum_frameintervals(struct file *filp, void *priv, | ||
989 | struct v4l2_frmivalenum *fival) | ||
990 | { | ||
991 | struct gspca_dev *gspca_dev = priv; | ||
992 | int mode = wxh_to_mode(gspca_dev, fival->width, fival->height); | ||
993 | __u32 i; | ||
994 | |||
995 | if (gspca_dev->cam.mode_framerates == NULL || | ||
996 | gspca_dev->cam.mode_framerates[mode].nrates == 0) | ||
997 | return -EINVAL; | ||
998 | |||
999 | if (fival->pixel_format != | ||
1000 | gspca_dev->cam.cam_mode[mode].pixelformat) | ||
1001 | return -EINVAL; | ||
1002 | |||
1003 | for (i = 0; i < gspca_dev->cam.mode_framerates[mode].nrates; i++) { | ||
1004 | if (fival->index == i) { | ||
1005 | fival->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1006 | fival->discrete.numerator = 1; | ||
1007 | fival->discrete.denominator = | ||
1008 | gspca_dev->cam.mode_framerates[mode].rates[i]; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | return -EINVAL; | ||
1014 | } | ||
1015 | |||
986 | static void gspca_release(struct video_device *vfd) | 1016 | static void gspca_release(struct video_device *vfd) |
987 | { | 1017 | { |
988 | struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); | 1018 | struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); |
989 | 1019 | ||
990 | PDEBUG(D_PROBE, "/dev/video%d released", gspca_dev->vdev.num); | 1020 | PDEBUG(D_PROBE, "%s released", |
1021 | video_device_node_name(&gspca_dev->vdev)); | ||
991 | 1022 | ||
992 | kfree(gspca_dev->usb_buf); | 1023 | kfree(gspca_dev->usb_buf); |
993 | kfree(gspca_dev); | 1024 | kfree(gspca_dev); |
@@ -1053,6 +1084,7 @@ static int dev_close(struct file *file) | |||
1053 | if (gspca_dev->capt_file == file) { | 1084 | if (gspca_dev->capt_file == file) { |
1054 | if (gspca_dev->streaming) { | 1085 | if (gspca_dev->streaming) { |
1055 | mutex_lock(&gspca_dev->usb_lock); | 1086 | mutex_lock(&gspca_dev->usb_lock); |
1087 | gspca_dev->usb_err = 0; | ||
1056 | gspca_stream_off(gspca_dev); | 1088 | gspca_stream_off(gspca_dev); |
1057 | mutex_unlock(&gspca_dev->usb_lock); | 1089 | mutex_unlock(&gspca_dev->usb_lock); |
1058 | } | 1090 | } |
@@ -1143,12 +1175,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
1143 | continue; | 1175 | continue; |
1144 | ctrls = &gspca_dev->sd_desc->ctrls[i]; | 1176 | ctrls = &gspca_dev->sd_desc->ctrls[i]; |
1145 | } | 1177 | } |
1178 | if (ctrls == NULL) | ||
1179 | return -EINVAL; | ||
1146 | } else { | 1180 | } else { |
1147 | ctrls = get_ctrl(gspca_dev, id); | 1181 | ctrls = get_ctrl(gspca_dev, id); |
1182 | if (ctrls == NULL) | ||
1183 | return -EINVAL; | ||
1148 | i = ctrls - gspca_dev->sd_desc->ctrls; | 1184 | i = ctrls - gspca_dev->sd_desc->ctrls; |
1149 | } | 1185 | } |
1150 | if (ctrls == NULL) | ||
1151 | return -EINVAL; | ||
1152 | memcpy(q_ctrl, ctrls, sizeof *q_ctrl); | 1186 | memcpy(q_ctrl, ctrls, sizeof *q_ctrl); |
1153 | if (gspca_dev->ctrl_inac & (1 << i)) | 1187 | if (gspca_dev->ctrl_inac & (1 << i)) |
1154 | q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 1188 | q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
@@ -1172,6 +1206,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1172 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); | 1206 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); |
1173 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1207 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1174 | return -ERESTARTSYS; | 1208 | return -ERESTARTSYS; |
1209 | gspca_dev->usb_err = 0; | ||
1175 | if (gspca_dev->present) | 1210 | if (gspca_dev->present) |
1176 | ret = ctrls->set(gspca_dev, ctrl->value); | 1211 | ret = ctrls->set(gspca_dev, ctrl->value); |
1177 | else | 1212 | else |
@@ -1193,6 +1228,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
1193 | 1228 | ||
1194 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1229 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1195 | return -ERESTARTSYS; | 1230 | return -ERESTARTSYS; |
1231 | gspca_dev->usb_err = 0; | ||
1196 | if (gspca_dev->present) | 1232 | if (gspca_dev->present) |
1197 | ret = ctrls->get(gspca_dev, &ctrl->value); | 1233 | ret = ctrls->get(gspca_dev, &ctrl->value); |
1198 | else | 1234 | else |
@@ -1307,6 +1343,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
1307 | /* stop streaming */ | 1343 | /* stop streaming */ |
1308 | if (gspca_dev->streaming) { | 1344 | if (gspca_dev->streaming) { |
1309 | mutex_lock(&gspca_dev->usb_lock); | 1345 | mutex_lock(&gspca_dev->usb_lock); |
1346 | gspca_dev->usb_err = 0; | ||
1310 | gspca_stream_off(gspca_dev); | 1347 | gspca_stream_off(gspca_dev); |
1311 | mutex_unlock(&gspca_dev->usb_lock); | 1348 | mutex_unlock(&gspca_dev->usb_lock); |
1312 | } | 1349 | } |
@@ -1398,6 +1435,7 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1398 | ret = -ERESTARTSYS; | 1435 | ret = -ERESTARTSYS; |
1399 | goto out; | 1436 | goto out; |
1400 | } | 1437 | } |
1438 | gspca_dev->usb_err = 0; | ||
1401 | gspca_stream_off(gspca_dev); | 1439 | gspca_stream_off(gspca_dev); |
1402 | mutex_unlock(&gspca_dev->usb_lock); | 1440 | mutex_unlock(&gspca_dev->usb_lock); |
1403 | 1441 | ||
@@ -1423,6 +1461,7 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, | |||
1423 | return -EINVAL; | 1461 | return -EINVAL; |
1424 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1462 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1425 | return -ERESTARTSYS; | 1463 | return -ERESTARTSYS; |
1464 | gspca_dev->usb_err = 0; | ||
1426 | if (gspca_dev->present) | 1465 | if (gspca_dev->present) |
1427 | ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); | 1466 | ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); |
1428 | else | 1467 | else |
@@ -1441,6 +1480,7 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, | |||
1441 | return -EINVAL; | 1480 | return -EINVAL; |
1442 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1481 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1443 | return -ERESTARTSYS; | 1482 | return -ERESTARTSYS; |
1483 | gspca_dev->usb_err = 0; | ||
1444 | if (gspca_dev->present) | 1484 | if (gspca_dev->present) |
1445 | ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); | 1485 | ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); |
1446 | else | 1486 | else |
@@ -1461,6 +1501,7 @@ static int vidioc_g_parm(struct file *filp, void *priv, | |||
1461 | 1501 | ||
1462 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1502 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1463 | return -ERESTARTSYS; | 1503 | return -ERESTARTSYS; |
1504 | gspca_dev->usb_err = 0; | ||
1464 | if (gspca_dev->present) | 1505 | if (gspca_dev->present) |
1465 | ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, | 1506 | ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, |
1466 | parm); | 1507 | parm); |
@@ -1490,6 +1531,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, | |||
1490 | 1531 | ||
1491 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1532 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1492 | return -ERESTARTSYS; | 1533 | return -ERESTARTSYS; |
1534 | gspca_dev->usb_err = 0; | ||
1493 | if (gspca_dev->present) | 1535 | if (gspca_dev->present) |
1494 | ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, | 1536 | ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, |
1495 | parm); | 1537 | parm); |
@@ -1613,7 +1655,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1613 | size -= PAGE_SIZE; | 1655 | size -= PAGE_SIZE; |
1614 | } | 1656 | } |
1615 | 1657 | ||
1616 | vma->vm_ops = (struct vm_operations_struct *) &gspca_vm_ops; | 1658 | vma->vm_ops = &gspca_vm_ops; |
1617 | vma->vm_private_data = frame; | 1659 | vma->vm_private_data = frame; |
1618 | gspca_vm_open(vma); | 1660 | gspca_vm_open(vma); |
1619 | ret = 0; | 1661 | ret = 0; |
@@ -1661,6 +1703,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, | |||
1661 | 1703 | ||
1662 | if (gspca_dev->sd_desc->dq_callback) { | 1704 | if (gspca_dev->sd_desc->dq_callback) { |
1663 | mutex_lock(&gspca_dev->usb_lock); | 1705 | mutex_lock(&gspca_dev->usb_lock); |
1706 | gspca_dev->usb_err = 0; | ||
1664 | if (gspca_dev->present) | 1707 | if (gspca_dev->present) |
1665 | gspca_dev->sd_desc->dq_callback(gspca_dev); | 1708 | gspca_dev->sd_desc->dq_callback(gspca_dev); |
1666 | mutex_unlock(&gspca_dev->usb_lock); | 1709 | mutex_unlock(&gspca_dev->usb_lock); |
@@ -1973,6 +2016,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { | |||
1973 | .vidioc_g_parm = vidioc_g_parm, | 2016 | .vidioc_g_parm = vidioc_g_parm, |
1974 | .vidioc_s_parm = vidioc_s_parm, | 2017 | .vidioc_s_parm = vidioc_s_parm, |
1975 | .vidioc_enum_framesizes = vidioc_enum_framesizes, | 2018 | .vidioc_enum_framesizes = vidioc_enum_framesizes, |
2019 | .vidioc_enum_frameintervals = vidioc_enum_frameintervals, | ||
1976 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 2020 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1977 | .vidioc_g_register = vidioc_g_register, | 2021 | .vidioc_g_register = vidioc_g_register, |
1978 | .vidioc_s_register = vidioc_s_register, | 2022 | .vidioc_s_register = vidioc_s_register, |
@@ -1988,7 +2032,6 @@ static struct video_device gspca_template = { | |||
1988 | .fops = &dev_fops, | 2032 | .fops = &dev_fops, |
1989 | .ioctl_ops = &dev_ioctl_ops, | 2033 | .ioctl_ops = &dev_ioctl_ops, |
1990 | .release = gspca_release, | 2034 | .release = gspca_release, |
1991 | .minor = -1, | ||
1992 | }; | 2035 | }; |
1993 | 2036 | ||
1994 | /* | 2037 | /* |
@@ -2049,9 +2092,6 @@ int gspca_dev_probe(struct usb_interface *intf, | |||
2049 | ret = sd_desc->init(gspca_dev); | 2092 | ret = sd_desc->init(gspca_dev); |
2050 | if (ret < 0) | 2093 | if (ret < 0) |
2051 | goto out; | 2094 | goto out; |
2052 | ret = gspca_set_alt0(gspca_dev); | ||
2053 | if (ret < 0) | ||
2054 | goto out; | ||
2055 | gspca_set_default_mode(gspca_dev); | 2095 | gspca_set_default_mode(gspca_dev); |
2056 | 2096 | ||
2057 | mutex_init(&gspca_dev->usb_lock); | 2097 | mutex_init(&gspca_dev->usb_lock); |
@@ -2073,7 +2113,7 @@ int gspca_dev_probe(struct usb_interface *intf, | |||
2073 | } | 2113 | } |
2074 | 2114 | ||
2075 | usb_set_intfdata(intf, gspca_dev); | 2115 | usb_set_intfdata(intf, gspca_dev); |
2076 | PDEBUG(D_PROBE, "/dev/video%d created", gspca_dev->vdev.num); | 2116 | PDEBUG(D_PROBE, "%s created", video_device_node_name(&gspca_dev->vdev)); |
2077 | return 0; | 2117 | return 0; |
2078 | out: | 2118 | out: |
2079 | kfree(gspca_dev->usb_buf); | 2119 | kfree(gspca_dev->usb_buf); |
@@ -2092,7 +2132,8 @@ void gspca_disconnect(struct usb_interface *intf) | |||
2092 | { | 2132 | { |
2093 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); | 2133 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); |
2094 | 2134 | ||
2095 | PDEBUG(D_PROBE, "/dev/video%d disconnect", gspca_dev->vdev.num); | 2135 | PDEBUG(D_PROBE, "%s disconnect", |
2136 | video_device_node_name(&gspca_dev->vdev)); | ||
2096 | mutex_lock(&gspca_dev->usb_lock); | 2137 | mutex_lock(&gspca_dev->usb_lock); |
2097 | gspca_dev->present = 0; | 2138 | gspca_dev->present = 0; |
2098 | 2139 | ||
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 181617355ec3..59c7941da999 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h | |||
@@ -45,11 +45,20 @@ extern int gspca_debug; | |||
45 | /* image transfers */ | 45 | /* image transfers */ |
46 | #define MAX_NURBS 4 /* max number of URBs */ | 46 | #define MAX_NURBS 4 /* max number of URBs */ |
47 | 47 | ||
48 | |||
49 | /* used to list framerates supported by a camera mode (resolution) */ | ||
50 | struct framerates { | ||
51 | int *rates; | ||
52 | int nrates; | ||
53 | }; | ||
54 | |||
48 | /* device information - set at probe time */ | 55 | /* device information - set at probe time */ |
49 | struct cam { | 56 | struct cam { |
50 | int bulk_size; /* buffer size when image transfer by bulk */ | 57 | int bulk_size; /* buffer size when image transfer by bulk */ |
51 | const struct v4l2_pix_format *cam_mode; /* size nmodes */ | 58 | const struct v4l2_pix_format *cam_mode; /* size nmodes */ |
52 | char nmodes; | 59 | char nmodes; |
60 | const struct framerates *mode_framerates; /* must have size nmode, | ||
61 | * just like cam_mode */ | ||
53 | __u8 bulk_nurbs; /* number of URBs in bulk mode | 62 | __u8 bulk_nurbs; /* number of URBs in bulk mode |
54 | * - cannot be > MAX_NURBS | 63 | * - cannot be > MAX_NURBS |
55 | * - when 0 and bulk_size != 0 means | 64 | * - when 0 and bulk_size != 0 means |
@@ -171,6 +180,7 @@ struct gspca_dev { | |||
171 | struct mutex usb_lock; /* usb exchange protection */ | 180 | struct mutex usb_lock; /* usb exchange protection */ |
172 | struct mutex read_lock; /* read protection */ | 181 | struct mutex read_lock; /* read protection */ |
173 | struct mutex queue_lock; /* ISOC queue protection */ | 182 | struct mutex queue_lock; /* ISOC queue protection */ |
183 | int usb_err; /* USB error - protected by usb_lock */ | ||
174 | #ifdef CONFIG_PM | 184 | #ifdef CONFIG_PM |
175 | char frozen; /* suspend - resume */ | 185 | char frozen; /* suspend - resume */ |
176 | #endif | 186 | #endif |
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 844fc1d886d1..4294c75e3b11 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c | |||
@@ -81,7 +81,7 @@ int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) | |||
81 | return (err < 0) ? err : 0; | 81 | return (err < 0) ? err : 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | int m5602_wait_for_i2c(struct sd *sd) | 84 | static int m5602_wait_for_i2c(struct sd *sd) |
85 | { | 85 | { |
86 | int err; | 86 | int err; |
87 | u8 data; | 87 | u8 data; |
@@ -388,7 +388,7 @@ static int m5602_probe(struct usb_interface *intf, | |||
388 | THIS_MODULE); | 388 | THIS_MODULE); |
389 | } | 389 | } |
390 | 390 | ||
391 | void m5602_disconnect(struct usb_interface *intf) | 391 | static void m5602_disconnect(struct usb_interface *intf) |
392 | { | 392 | { |
393 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); | 393 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); |
394 | struct sd *sd = (struct sd *) gspca_dev; | 394 | struct sd *sd = (struct sd *) gspca_dev; |
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index c2739d6605a1..923cdd5f7a6b 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c | |||
@@ -439,7 +439,7 @@ int ov9650_start(struct sd *sd) | |||
439 | err = m5602_write_bridge(sd, res_init_ov9650[i][1], | 439 | err = m5602_write_bridge(sd, res_init_ov9650[i][1], |
440 | res_init_ov9650[i][2]); | 440 | res_init_ov9650[i][2]); |
441 | else if (res_init_ov9650[i][0] == SENSOR) { | 441 | else if (res_init_ov9650[i][0] == SENSOR) { |
442 | u8 data = res_init_ov9650[i][2]; | 442 | data = res_init_ov9650[i][2]; |
443 | err = m5602_write_sensor(sd, | 443 | err = m5602_write_sensor(sd, |
444 | res_init_ov9650[i][1], &data, 1); | 444 | res_init_ov9650[i][1], &data, 1); |
445 | } | 445 | } |
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index a27afeb6f39b..aa2f3c7e2cb5 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c | |||
@@ -525,7 +525,10 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | |||
525 | err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); | 525 | err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); |
526 | if (err < 0) | 526 | if (err < 0) |
527 | return err; | 527 | return err; |
528 | data = (data & 0xfe) | !val; | 528 | if (val) |
529 | data &= 0xfe; | ||
530 | else | ||
531 | data |= 0x01; | ||
529 | err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); | 532 | err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); |
530 | return err; | 533 | return err; |
531 | } | 534 | } |
@@ -570,7 +573,10 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | |||
570 | err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); | 573 | err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); |
571 | if (err < 0) | 574 | if (err < 0) |
572 | return err; | 575 | return err; |
573 | data = (data & 0xfe) | !val; | 576 | if (val) |
577 | data &= 0xfe; | ||
578 | else | ||
579 | data |= 0x01; | ||
574 | err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); | 580 | err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); |
575 | return err; | 581 | return err; |
576 | } | 582 | } |
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 126d968dd9e0..9154870e07d2 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c | |||
@@ -67,7 +67,7 @@ MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); | |||
67 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
68 | 68 | ||
69 | /* global parameters */ | 69 | /* global parameters */ |
70 | int force_sensor_type = -1; | 70 | static int force_sensor_type = -1; |
71 | module_param(force_sensor_type, int, 0644); | 71 | module_param(force_sensor_type, int, 0644); |
72 | MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); | 72 | MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); |
73 | 73 | ||
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index ad9ec339981d..b4f965731244 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c | |||
@@ -1982,7 +1982,7 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n) | |||
1982 | { | 1982 | { |
1983 | int ret; | 1983 | int ret; |
1984 | 1984 | ||
1985 | *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value); | 1985 | *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value); |
1986 | 1986 | ||
1987 | ret = usb_control_msg(sd->gspca_dev.dev, | 1987 | ret = usb_control_msg(sd->gspca_dev.dev, |
1988 | usb_sndctrlpipe(sd->gspca_dev.dev, 0), | 1988 | usb_sndctrlpipe(sd->gspca_dev.dev, 0), |
@@ -2021,9 +2021,9 @@ static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value) | |||
2021 | if (rc < 0) | 2021 | if (rc < 0) |
2022 | return rc; | 2022 | return rc; |
2023 | 2023 | ||
2024 | do | 2024 | do { |
2025 | rc = reg_r(sd, R511_I2C_CTL); | 2025 | rc = reg_r(sd, R511_I2C_CTL); |
2026 | while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ | 2026 | } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ |
2027 | 2027 | ||
2028 | if (rc < 0) | 2028 | if (rc < 0) |
2029 | return rc; | 2029 | return rc; |
@@ -2055,9 +2055,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg) | |||
2055 | if (rc < 0) | 2055 | if (rc < 0) |
2056 | return rc; | 2056 | return rc; |
2057 | 2057 | ||
2058 | do | 2058 | do { |
2059 | rc = reg_r(sd, R511_I2C_CTL); | 2059 | rc = reg_r(sd, R511_I2C_CTL); |
2060 | while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ | 2060 | } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ |
2061 | 2061 | ||
2062 | if (rc < 0) | 2062 | if (rc < 0) |
2063 | return rc; | 2063 | return rc; |
@@ -2081,9 +2081,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg) | |||
2081 | if (rc < 0) | 2081 | if (rc < 0) |
2082 | return rc; | 2082 | return rc; |
2083 | 2083 | ||
2084 | do | 2084 | do { |
2085 | rc = reg_r(sd, R511_I2C_CTL); | 2085 | rc = reg_r(sd, R511_I2C_CTL); |
2086 | while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ | 2086 | } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ |
2087 | 2087 | ||
2088 | if (rc < 0) | 2088 | if (rc < 0) |
2089 | return rc; | 2089 | return rc; |
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 74acceea8094..de0b66c4b56e 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c | |||
@@ -90,6 +90,9 @@ struct sd { | |||
90 | unsigned char autogain; | 90 | unsigned char autogain; |
91 | __u8 hflip; | 91 | __u8 hflip; |
92 | __u8 vflip; | 92 | __u8 vflip; |
93 | u8 flags; | ||
94 | #define FL_HFLIP 0x01 /* mirrored by default */ | ||
95 | #define FL_VFLIP 0x02 /* vertical flipped by default */ | ||
93 | 96 | ||
94 | u8 sof_read; | 97 | u8 sof_read; |
95 | u8 autogain_ignore_frames; | 98 | u8 autogain_ignore_frames; |
@@ -552,6 +555,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
552 | sd->autogain = AUTOGAIN_DEF; | 555 | sd->autogain = AUTOGAIN_DEF; |
553 | sd->hflip = HFLIP_DEF; | 556 | sd->hflip = HFLIP_DEF; |
554 | sd->vflip = VFLIP_DEF; | 557 | sd->vflip = VFLIP_DEF; |
558 | sd->flags = id->driver_info; | ||
555 | return 0; | 559 | return 0; |
556 | } | 560 | } |
557 | 561 | ||
@@ -708,10 +712,17 @@ static int sethvflip(struct gspca_dev *gspca_dev) | |||
708 | { | 712 | { |
709 | struct sd *sd = (struct sd *) gspca_dev; | 713 | struct sd *sd = (struct sd *) gspca_dev; |
710 | int ret; | 714 | int ret; |
711 | __u8 data; | 715 | u8 data, hflip, vflip; |
716 | |||
717 | hflip = sd->hflip; | ||
718 | if (sd->flags & FL_HFLIP) | ||
719 | hflip = !hflip; | ||
720 | vflip = sd->vflip; | ||
721 | if (sd->flags & FL_VFLIP) | ||
722 | vflip = !vflip; | ||
712 | 723 | ||
713 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 724 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
714 | data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00); | 725 | data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); |
715 | if (0 <= ret) | 726 | if (0 <= ret) |
716 | ret = reg_w(gspca_dev, 0x21, data); | 727 | ret = reg_w(gspca_dev, 0x21, data); |
717 | /* load registers to sensor (Bit 0, auto clear) */ | 728 | /* load registers to sensor (Bit 0, auto clear) */ |
@@ -1218,15 +1229,15 @@ static struct sd_desc sd_desc = { | |||
1218 | }; | 1229 | }; |
1219 | 1230 | ||
1220 | /* -- module initialisation -- */ | 1231 | /* -- module initialisation -- */ |
1221 | static __devinitdata struct usb_device_id device_table[] = { | 1232 | static const struct usb_device_id device_table[] __devinitconst = { |
1222 | {USB_DEVICE(0x06f8, 0x3009)}, | 1233 | {USB_DEVICE(0x06f8, 0x3009)}, |
1223 | {USB_DEVICE(0x093a, 0x2620)}, | 1234 | {USB_DEVICE(0x093a, 0x2620)}, |
1224 | {USB_DEVICE(0x093a, 0x2621)}, | 1235 | {USB_DEVICE(0x093a, 0x2621)}, |
1225 | {USB_DEVICE(0x093a, 0x2622)}, | 1236 | {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, |
1226 | {USB_DEVICE(0x093a, 0x2624)}, | 1237 | {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, |
1227 | {USB_DEVICE(0x093a, 0x2626)}, | 1238 | {USB_DEVICE(0x093a, 0x2626)}, |
1228 | {USB_DEVICE(0x093a, 0x2628)}, | 1239 | {USB_DEVICE(0x093a, 0x2628)}, |
1229 | {USB_DEVICE(0x093a, 0x2629)}, | 1240 | {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, |
1230 | {USB_DEVICE(0x093a, 0x262a)}, | 1241 | {USB_DEVICE(0x093a, 0x262a)}, |
1231 | {USB_DEVICE(0x093a, 0x262c)}, | 1242 | {USB_DEVICE(0x093a, 0x262c)}, |
1232 | {} | 1243 | {} |
@@ -1234,7 +1245,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
1234 | MODULE_DEVICE_TABLE(usb, device_table); | 1245 | MODULE_DEVICE_TABLE(usb, device_table); |
1235 | 1246 | ||
1236 | /* -- device connect -- */ | 1247 | /* -- device connect -- */ |
1237 | static int sd_probe(struct usb_interface *intf, | 1248 | static int __devinit sd_probe(struct usb_interface *intf, |
1238 | const struct usb_device_id *id) | 1249 | const struct usb_device_id *id) |
1239 | { | 1250 | { |
1240 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 1251 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index e5697a6345e8..42cfcdfd8f4f 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c | |||
@@ -863,7 +863,7 @@ static struct sd_desc sd_desc = { | |||
863 | }; | 863 | }; |
864 | 864 | ||
865 | /* -- module initialisation -- */ | 865 | /* -- module initialisation -- */ |
866 | static __devinitdata struct usb_device_id device_table[] = { | 866 | static const struct usb_device_id device_table[] __devinitconst = { |
867 | {USB_DEVICE(0x093a, 0x2600)}, | 867 | {USB_DEVICE(0x093a, 0x2600)}, |
868 | {USB_DEVICE(0x093a, 0x2601)}, | 868 | {USB_DEVICE(0x093a, 0x2601)}, |
869 | {USB_DEVICE(0x093a, 0x2603)}, | 869 | {USB_DEVICE(0x093a, 0x2603)}, |
@@ -875,7 +875,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
875 | MODULE_DEVICE_TABLE(usb, device_table); | 875 | MODULE_DEVICE_TABLE(usb, device_table); |
876 | 876 | ||
877 | /* -- device connect -- */ | 877 | /* -- device connect -- */ |
878 | static int sd_probe(struct usb_interface *intf, | 878 | static int __devinit sd_probe(struct usb_interface *intf, |
879 | const struct usb_device_id *id) | 879 | const struct usb_device_id *id) |
880 | { | 880 | { |
881 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 881 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index b1944a7cbb0f..4cff8035614f 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c | |||
@@ -1158,7 +1158,7 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) | |||
1158 | return i2c_w(gspca_dev, row); | 1158 | return i2c_w(gspca_dev, row); |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) | 1161 | static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) |
1162 | { | 1162 | { |
1163 | struct sd *sd = (struct sd *) gspca_dev; | 1163 | struct sd *sd = (struct sd *) gspca_dev; |
1164 | u8 row[8]; | 1164 | u8 row[8]; |
@@ -1183,7 +1183,7 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) | |||
1183 | return 0; | 1183 | return 0; |
1184 | } | 1184 | } |
1185 | 1185 | ||
1186 | int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) | 1186 | static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) |
1187 | { | 1187 | { |
1188 | struct sd *sd = (struct sd *) gspca_dev; | 1188 | struct sd *sd = (struct sd *) gspca_dev; |
1189 | u8 row[8]; | 1189 | u8 row[8]; |
@@ -1476,8 +1476,9 @@ static int sn9c20x_input_init(struct gspca_dev *gspca_dev) | |||
1476 | if (input_register_device(sd->input_dev)) | 1476 | if (input_register_device(sd->input_dev)) |
1477 | return -EINVAL; | 1477 | return -EINVAL; |
1478 | 1478 | ||
1479 | sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%d", | 1479 | sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%s-%s", |
1480 | gspca_dev->vdev.minor); | 1480 | gspca_dev->dev->bus->bus_name, |
1481 | gspca_dev->dev->devpath); | ||
1481 | 1482 | ||
1482 | if (IS_ERR(sd->input_task)) | 1483 | if (IS_ERR(sd->input_task)) |
1483 | return -EINVAL; | 1484 | return -EINVAL; |
@@ -2174,8 +2175,7 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) | |||
2174 | } | 2175 | } |
2175 | 2176 | ||
2176 | #define HW_WIN(mode, hstart, vstart) \ | 2177 | #define HW_WIN(mode, hstart, vstart) \ |
2177 | ((const u8 []){hstart & 0xff, hstart >> 8, \ | 2178 | ((const u8 []){hstart, 0, vstart, 0, \ |
2178 | vstart & 0xff, vstart >> 8, \ | ||
2179 | (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ | 2179 | (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ |
2180 | (mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) | 2180 | (mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) |
2181 | 2181 | ||
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 5be95bc65138..ddff2b5ee5c2 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c | |||
@@ -1226,7 +1226,7 @@ static const struct sd_desc sd_desc = { | |||
1226 | .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge | 1226 | .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge |
1227 | 1227 | ||
1228 | 1228 | ||
1229 | static __devinitdata struct usb_device_id device_table[] = { | 1229 | static const struct usb_device_id device_table[] __devinitconst = { |
1230 | {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */ | 1230 | {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */ |
1231 | {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */ | 1231 | {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */ |
1232 | #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE | 1232 | #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE |
@@ -1257,7 +1257,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
1257 | MODULE_DEVICE_TABLE(usb, device_table); | 1257 | MODULE_DEVICE_TABLE(usb, device_table); |
1258 | 1258 | ||
1259 | /* -- device connect -- */ | 1259 | /* -- device connect -- */ |
1260 | static int sd_probe(struct usb_interface *intf, | 1260 | static int __devinit sd_probe(struct usb_interface *intf, |
1261 | const struct usb_device_id *id) | 1261 | const struct usb_device_id *id) |
1262 | { | 1262 | { |
1263 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 1263 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index ab28cc23e415..39257e4e074f 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c | |||
@@ -685,7 +685,7 @@ static struct sd_desc sd_desc = { | |||
685 | }; | 685 | }; |
686 | 686 | ||
687 | /* -- module initialisation -- */ | 687 | /* -- module initialisation -- */ |
688 | static __devinitdata struct usb_device_id device_table[] = { | 688 | static const struct usb_device_id device_table[] __devinitconst = { |
689 | {USB_DEVICE(0x06e1, 0xa190)}, | 689 | {USB_DEVICE(0x06e1, 0xa190)}, |
690 | /*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 | 690 | /*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 |
691 | {USB_DEVICE(0x0733, 0x0430)}, */ | 691 | {USB_DEVICE(0x0733, 0x0430)}, */ |
@@ -696,7 +696,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
696 | MODULE_DEVICE_TABLE(usb, device_table); | 696 | MODULE_DEVICE_TABLE(usb, device_table); |
697 | 697 | ||
698 | /* -- device connect -- */ | 698 | /* -- device connect -- */ |
699 | static int sd_probe(struct usb_interface *intf, | 699 | static int __devinit sd_probe(struct usb_interface *intf, |
700 | const struct usb_device_id *id) | 700 | const struct usb_device_id *id) |
701 | { | 701 | { |
702 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | 702 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), |
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 8e23320d7ab7..2e2935532d99 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c | |||
@@ -126,12 +126,14 @@ static const struct v4l2_pix_format vga_mode[] = { | |||
126 | }; | 126 | }; |
127 | 127 | ||
128 | /* -- read a register -- */ | 128 | /* -- read a register -- */ |
129 | static int reg_r(struct gspca_dev *gspca_dev, | 129 | static u8 reg_r(struct gspca_dev *gspca_dev, |
130 | __u16 index) | 130 | __u16 index) |
131 | { | 131 | { |
132 | struct usb_device *dev = gspca_dev->dev; | 132 | struct usb_device *dev = gspca_dev->dev; |
133 | int ret; | 133 | int ret; |
134 | 134 | ||
135 | if (gspca_dev->usb_err < 0) | ||
136 | return 0; | ||
135 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | 137 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
136 | 0x00, | 138 | 0x00, |
137 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 139 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
@@ -141,18 +143,21 @@ static int reg_r(struct gspca_dev *gspca_dev, | |||
141 | 500); | 143 | 500); |
142 | if (ret < 0) { | 144 | if (ret < 0) { |
143 | PDEBUG(D_ERR, "reg_r err %d", ret); | 145 | PDEBUG(D_ERR, "reg_r err %d", ret); |
144 | return ret; | 146 | gspca_dev->usb_err = ret; |
147 | return 0; | ||
145 | } | 148 | } |
146 | return gspca_dev->usb_buf[0]; | 149 | return gspca_dev->usb_buf[0]; |
147 | } | 150 | } |
148 | 151 | ||
149 | /* -- write a register -- */ | 152 | /* -- write a register -- */ |
150 | static int reg_w(struct gspca_dev *gspca_dev, | 153 | static void reg_w(struct gspca_dev *gspca_dev, |
151 | __u16 index, __u16 value) | 154 | __u16 index, __u16 value) |
152 | { | 155 | { |
153 | struct usb_device *dev = gspca_dev->dev; | 156 | struct usb_device *dev = gspca_dev->dev; |
154 | int ret; | 157 | int ret; |
155 | 158 | ||
159 | if (gspca_dev->usb_err < 0) | ||
160 | return; | ||
156 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 161 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
157 | 0x01, | 162 | 0x01, |
158 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 163 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
@@ -161,13 +166,14 @@ static int reg_w(struct gspca_dev *gspca_dev, | |||
161 | NULL, | 166 | NULL, |
162 | 0, | 167 | 0, |
163 | 500); | 168 | 500); |
164 | if (ret < 0) | 169 | if (ret < 0) { |
165 | PDEBUG(D_ERR, "reg_w err %d", ret); | 170 | PDEBUG(D_ERR, "reg_w err %d", ret); |
166 | return ret; | 171 | gspca_dev->usb_err = ret; |
172 | } | ||
167 | } | 173 | } |
168 | 174 | ||
169 | /* -- get a bulk value (4 bytes) -- */ | 175 | /* -- get a bulk value (4 bytes) -- */ |
170 | static int rcv_val(struct gspca_dev *gspca_dev, | 176 | static void rcv_val(struct gspca_dev *gspca_dev, |
171 | int ads) | 177 | int ads) |
172 | { | 178 | { |
173 | struct usb_device *dev = gspca_dev->dev; | 179 | struct usb_device *dev = gspca_dev->dev; |
@@ -182,17 +188,22 @@ static int rcv_val(struct gspca_dev *gspca_dev, | |||
182 | reg_w(gspca_dev, 0x63a, 0); | 188 | reg_w(gspca_dev, 0x63a, 0); |
183 | reg_w(gspca_dev, 0x63b, 0); | 189 | reg_w(gspca_dev, 0x63b, 0); |
184 | reg_w(gspca_dev, 0x630, 5); | 190 | reg_w(gspca_dev, 0x630, 5); |
191 | if (gspca_dev->usb_err < 0) | ||
192 | return; | ||
185 | ret = usb_bulk_msg(dev, | 193 | ret = usb_bulk_msg(dev, |
186 | usb_rcvbulkpipe(dev, 0x05), | 194 | usb_rcvbulkpipe(dev, 0x05), |
187 | gspca_dev->usb_buf, | 195 | gspca_dev->usb_buf, |
188 | 4, /* length */ | 196 | 4, /* length */ |
189 | &alen, | 197 | &alen, |
190 | 500); /* timeout in milliseconds */ | 198 | 500); /* timeout in milliseconds */ |
191 | return ret; | 199 | if (ret < 0) { |
200 | PDEBUG(D_ERR, "rcv_val err %d", ret); | ||
201 | gspca_dev->usb_err = ret; | ||
202 | } | ||
192 | } | 203 | } |
193 | 204 | ||
194 | /* -- send a bulk value -- */ | 205 | /* -- send a bulk value -- */ |
195 | static int snd_val(struct gspca_dev *gspca_dev, | 206 | static void snd_val(struct gspca_dev *gspca_dev, |
196 | int ads, | 207 | int ads, |
197 | unsigned int val) | 208 | unsigned int val) |
198 | { | 209 | { |
@@ -201,16 +212,9 @@ static int snd_val(struct gspca_dev *gspca_dev, | |||
201 | __u8 seq = 0; | 212 | __u8 seq = 0; |
202 | 213 | ||
203 | if (ads == 0x003f08) { | 214 | if (ads == 0x003f08) { |
204 | ret = reg_r(gspca_dev, 0x0704); | 215 | reg_r(gspca_dev, 0x0704); |
205 | if (ret < 0) | 216 | seq = reg_r(gspca_dev, 0x0705); |
206 | goto ko; | 217 | reg_r(gspca_dev, 0x0650); |
207 | ret = reg_r(gspca_dev, 0x0705); | ||
208 | if (ret < 0) | ||
209 | goto ko; | ||
210 | seq = ret; /* keep the sequence number */ | ||
211 | ret = reg_r(gspca_dev, 0x0650); | ||
212 | if (ret < 0) | ||
213 | goto ko; | ||
214 | reg_w(gspca_dev, 0x654, seq); | 218 | reg_w(gspca_dev, 0x654, seq); |
215 | } else { | 219 | } else { |
216 | reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); | 220 | reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); |
@@ -223,6 +227,8 @@ static int snd_val(struct gspca_dev *gspca_dev, | |||
223 | reg_w(gspca_dev, 0x65a, 0); | 227 | reg_w(gspca_dev, 0x65a, 0); |
224 | reg_w(gspca_dev, 0x65b, 0); | 228 | reg_w(gspca_dev, 0x65b, 0); |
225 | reg_w(gspca_dev, 0x650, 5); | 229 | reg_w(gspca_dev, 0x650, 5); |
230 | if (gspca_dev->usb_err < 0) | ||
231 | return; | ||
226 | gspca_dev->usb_buf[0] = val >> 24; | 232 | gspca_dev->usb_buf[0] = val >> 24; |
227 | gspca_dev->usb_buf[1] = val >> 16; | 233 | gspca_dev->usb_buf[1] = val >> 16; |
228 | gspca_dev->usb_buf[2] = val >> 8; | 234 | gspca_dev->usb_buf[2] = val >> 8; |
@@ -233,24 +239,23 @@ static int snd_val(struct gspca_dev *gspca_dev, | |||
233 | 4, | 239 | 4, |
234 | &alen, | 240 | &alen, |
235 | 500); /* timeout in milliseconds */ | 241 | 500); /* timeout in milliseconds */ |
236 | if (ret < 0) | 242 | if (ret < 0) { |
237 | goto ko; | 243 | PDEBUG(D_ERR, "snd_val err %d", ret); |
238 | if (ads == 0x003f08) { | 244 | gspca_dev->usb_err = ret; |
239 | seq += 4; | 245 | } else { |
240 | seq &= 0x3f; | 246 | if (ads == 0x003f08) { |
241 | reg_w(gspca_dev, 0x705, seq); | 247 | seq += 4; |
248 | seq &= 0x3f; | ||
249 | reg_w(gspca_dev, 0x705, seq); | ||
250 | } | ||
242 | } | 251 | } |
243 | return ret; | ||
244 | ko: | ||
245 | PDEBUG(D_ERR, "snd_val err %d", ret); | ||
246 | return ret; | ||
247 | } | 252 | } |
248 | 253 | ||
249 | /* set a camera parameter */ | 254 | /* set a camera parameter */ |
250 | static int set_par(struct gspca_dev *gspca_dev, | 255 | static void set_par(struct gspca_dev *gspca_dev, |
251 | int parval) | 256 | int parval) |
252 | { | 257 | { |
253 | return snd_val(gspca_dev, 0x003f08, parval); | 258 | snd_val(gspca_dev, 0x003f08, parval); |
254 | } | 259 | } |
255 | 260 | ||
256 | static void setbrightness(struct gspca_dev *gspca_dev) | 261 | static void setbrightness(struct gspca_dev *gspca_dev) |
@@ -311,18 +316,18 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
311 | /* this function is called at probe and resume time */ | 316 | /* this function is called at probe and resume time */ |
312 | static int sd_init(struct gspca_dev *gspca_dev) | 317 | static int sd_init(struct gspca_dev *gspca_dev) |
313 | { | 318 | { |
314 | int ret; | 319 | u8 ret; |
315 | 320 | ||
316 | /* check if the device responds */ | 321 | /* check if the device responds */ |
317 | usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); | 322 | usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); |
318 | ret = reg_r(gspca_dev, 0x0740); | 323 | ret = reg_r(gspca_dev, 0x0740); |
319 | if (ret < 0) | 324 | if (gspca_dev->usb_err >= 0) { |
320 | return ret; | 325 | if (ret != 0xff) { |
321 | if (ret != 0xff) { | 326 | PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); |
322 | PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); | 327 | gspca_dev->usb_err = -EIO; |
323 | return -1; | 328 | } |
324 | } | 329 | } |
325 | return 0; | 330 | return gspca_dev->usb_err; |
326 | } | 331 | } |
327 | 332 | ||
328 | /* -- start the camera -- */ | 333 | /* -- start the camera -- */ |
@@ -357,15 +362,12 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
357 | if (ret < 0) { | 362 | if (ret < 0) { |
358 | PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed", | 363 | PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed", |
359 | gspca_dev->iface, gspca_dev->alt); | 364 | gspca_dev->iface, gspca_dev->alt); |
365 | gspca_dev->usb_err = ret; | ||
360 | goto out; | 366 | goto out; |
361 | } | 367 | } |
362 | ret = reg_r(gspca_dev, 0x0630); | 368 | reg_r(gspca_dev, 0x0630); |
363 | if (ret < 0) | ||
364 | goto out; | ||
365 | rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ | 369 | rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ |
366 | ret = reg_r(gspca_dev, 0x0650); | 370 | reg_r(gspca_dev, 0x0650); |
367 | if (ret < 0) | ||
368 | goto out; | ||
369 | snd_val(gspca_dev, 0x000020, 0xffffffff); | 371 | snd_val(gspca_dev, 0x000020, 0xffffffff); |
370 | reg_w(gspca_dev, 0x0620, 0); | 372 | reg_w(gspca_dev, 0x0620, 0); |
371 | reg_w(gspca_dev, 0x0630, 0); | 373 | reg_w(gspca_dev, 0x0630, 0); |
@@ -384,11 +386,11 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
384 | /* start the video flow */ | 386 | /* start the video flow */ |
385 | set_par(gspca_dev, 0x01000000); | 387 | set_par(gspca_dev, 0x01000000); |
386 | set_par(gspca_dev, 0x01000000); | 388 | set_par(gspca_dev, 0x01000000); |
387 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); | 389 | if (gspca_dev->usb_err >= 0) |
388 | return 0; | 390 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", |
391 | gspca_dev->alt); | ||
389 | out: | 392 | out: |
390 | PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); | 393 | return gspca_dev->usb_err; |
391 | return ret; | ||
392 | } | 394 | } |
393 | 395 | ||
394 | static void sd_stopN(struct gspca_dev *gspca_dev) | 396 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -456,7 +458,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |||
456 | sd->brightness = val; | 458 | sd->brightness = val; |
457 | if (gspca_dev->streaming) | 459 | if (gspca_dev->streaming) |
458 | setbrightness(gspca_dev); | 460 | setbrightness(gspca_dev); |
459 | return 0; | 461 | return gspca_dev->usb_err; |
460 | } | 462 | } |
461 | 463 | ||
462 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | 464 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -474,7 +476,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |||
474 | sd->contrast = val; | 476 | sd->contrast = val; |
475 | if (gspca_dev->streaming) | 477 | if (gspca_dev->streaming) |
476 | setcontrast(gspca_dev); | 478 | setcontrast(gspca_dev); |
477 | return 0; | 479 | return gspca_dev->usb_err; |
478 | } | 480 | } |
479 | 481 | ||
480 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | 482 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -492,7 +494,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) | |||
492 | sd->colors = val; | 494 | sd->colors = val; |
493 | if (gspca_dev->streaming) | 495 | if (gspca_dev->streaming) |
494 | setcolors(gspca_dev); | 496 | setcolors(gspca_dev); |
495 | return 0; | 497 | return gspca_dev->usb_err; |
496 | } | 498 | } |
497 | 499 | ||
498 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | 500 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -510,7 +512,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) | |||
510 | sd->lightfreq = val; | 512 | sd->lightfreq = val; |
511 | if (gspca_dev->streaming) | 513 | if (gspca_dev->streaming) |
512 | setfreq(gspca_dev); | 514 | setfreq(gspca_dev); |
513 | return 0; | 515 | return gspca_dev->usb_err; |
514 | } | 516 | } |
515 | 517 | ||
516 | static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) | 518 | static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -552,7 +554,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, | |||
552 | sd->quality = jcomp->quality; | 554 | sd->quality = jcomp->quality; |
553 | if (gspca_dev->streaming) | 555 | if (gspca_dev->streaming) |
554 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | 556 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); |
555 | return 0; | 557 | return gspca_dev->usb_err; |
556 | } | 558 | } |
557 | 559 | ||
558 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | 560 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, |
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 72bf3b4f0a31..716df6b15fc5 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c | |||
@@ -460,13 +460,17 @@ static void reg_r(struct gspca_dev *gspca_dev, | |||
460 | u16 index, | 460 | u16 index, |
461 | u16 len) | 461 | u16 len) |
462 | { | 462 | { |
463 | int ret; | ||
464 | |||
463 | #ifdef GSPCA_DEBUG | 465 | #ifdef GSPCA_DEBUG |
464 | if (len > USB_BUF_SZ) { | 466 | if (len > USB_BUF_SZ) { |
465 | err("reg_r: buffer overflow"); | 467 | err("reg_r: buffer overflow"); |
466 | return; | 468 | return; |
467 | } | 469 | } |
468 | #endif | 470 | #endif |
469 | usb_control_msg(gspca_dev->dev, | 471 | if (gspca_dev->usb_err < 0) |
472 | return; | ||
473 | ret = usb_control_msg(gspca_dev->dev, | ||
470 | usb_rcvctrlpipe(gspca_dev->dev, 0), | 474 | usb_rcvctrlpipe(gspca_dev->dev, 0), |
471 | req, | 475 | req, |
472 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 476 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
@@ -474,6 +478,10 @@ static void reg_r(struct gspca_dev *gspca_dev, | |||
474 | index, | 478 | index, |
475 | len ? gspca_dev->usb_buf : NULL, len, | 479 | len ? gspca_dev->usb_buf : NULL, len, |
476 | 500); | 480 | 500); |
481 | if (ret < 0) { | ||
482 | PDEBUG(D_ERR, "reg_r err %d", ret); | ||
483 | gspca_dev->usb_err = ret; | ||
484 | } | ||
477 | } | 485 | } |
478 | 486 | ||
479 | /* write one byte */ | 487 | /* write one byte */ |
@@ -483,40 +491,55 @@ static void reg_w_1(struct gspca_dev *gspca_dev, | |||
483 | u16 index, | 491 | u16 index, |
484 | u16 byte) | 492 | u16 byte) |
485 | { | 493 | { |
494 | int ret; | ||
495 | |||
496 | if (gspca_dev->usb_err < 0) | ||
497 | return; | ||
486 | gspca_dev->usb_buf[0] = byte; | 498 | gspca_dev->usb_buf[0] = byte; |
487 | usb_control_msg(gspca_dev->dev, | 499 | ret = usb_control_msg(gspca_dev->dev, |
488 | usb_sndctrlpipe(gspca_dev->dev, 0), | 500 | usb_sndctrlpipe(gspca_dev->dev, 0), |
489 | req, | 501 | req, |
490 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 502 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
491 | value, index, | 503 | value, index, |
492 | gspca_dev->usb_buf, 1, | 504 | gspca_dev->usb_buf, 1, |
493 | 500); | 505 | 500); |
506 | if (ret < 0) { | ||
507 | PDEBUG(D_ERR, "reg_w_1 err %d", ret); | ||
508 | gspca_dev->usb_err = ret; | ||
509 | } | ||
494 | } | 510 | } |
495 | 511 | ||
496 | /* write req / index / value */ | 512 | /* write req / index / value */ |
497 | static int reg_w_riv(struct usb_device *dev, | 513 | static void reg_w_riv(struct gspca_dev *gspca_dev, |
498 | u8 req, u16 index, u16 value) | 514 | u8 req, u16 index, u16 value) |
499 | { | 515 | { |
516 | struct usb_device *dev = gspca_dev->dev; | ||
500 | int ret; | 517 | int ret; |
501 | 518 | ||
519 | if (gspca_dev->usb_err < 0) | ||
520 | return; | ||
502 | ret = usb_control_msg(dev, | 521 | ret = usb_control_msg(dev, |
503 | usb_sndctrlpipe(dev, 0), | 522 | usb_sndctrlpipe(dev, 0), |
504 | req, | 523 | req, |
505 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 524 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
506 | value, index, NULL, 0, 500); | 525 | value, index, NULL, 0, 500); |
507 | PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", | 526 | if (ret < 0) { |
508 | req, index, value, ret); | 527 | PDEBUG(D_ERR, "reg_w_riv err %d", ret); |
509 | if (ret < 0) | 528 | gspca_dev->usb_err = ret; |
510 | PDEBUG(D_ERR, "reg write: error %d", ret); | 529 | return; |
511 | return ret; | 530 | } |
531 | PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x", | ||
532 | req, index, value); | ||
512 | } | 533 | } |
513 | 534 | ||
514 | /* read 1 byte */ | 535 | /* read 1 byte */ |
515 | static int reg_r_1(struct gspca_dev *gspca_dev, | 536 | static u8 reg_r_1(struct gspca_dev *gspca_dev, |
516 | u16 value) /* wValue */ | 537 | u16 value) /* wValue */ |
517 | { | 538 | { |
518 | int ret; | 539 | int ret; |
519 | 540 | ||
541 | if (gspca_dev->usb_err < 0) | ||
542 | return 0; | ||
520 | ret = usb_control_msg(gspca_dev->dev, | 543 | ret = usb_control_msg(gspca_dev->dev, |
521 | usb_rcvctrlpipe(gspca_dev->dev, 0), | 544 | usb_rcvctrlpipe(gspca_dev->dev, 0), |
522 | 0x20, /* request */ | 545 | 0x20, /* request */ |
@@ -527,19 +550,22 @@ static int reg_r_1(struct gspca_dev *gspca_dev, | |||
527 | 500); /* timeout */ | 550 | 500); /* timeout */ |
528 | if (ret < 0) { | 551 | if (ret < 0) { |
529 | PDEBUG(D_ERR, "reg_r_1 err %d", ret); | 552 | PDEBUG(D_ERR, "reg_r_1 err %d", ret); |
553 | gspca_dev->usb_err = ret; | ||
530 | return 0; | 554 | return 0; |
531 | } | 555 | } |
532 | return gspca_dev->usb_buf[0]; | 556 | return gspca_dev->usb_buf[0]; |
533 | } | 557 | } |
534 | 558 | ||
535 | /* read 1 or 2 bytes - returns < 0 if error */ | 559 | /* read 1 or 2 bytes */ |
536 | static int reg_r_12(struct gspca_dev *gspca_dev, | 560 | static u16 reg_r_12(struct gspca_dev *gspca_dev, |
537 | u8 req, /* bRequest */ | 561 | u8 req, /* bRequest */ |
538 | u16 index, /* wIndex */ | 562 | u16 index, /* wIndex */ |
539 | u16 length) /* wLength (1 or 2 only) */ | 563 | u16 length) /* wLength (1 or 2 only) */ |
540 | { | 564 | { |
541 | int ret; | 565 | int ret; |
542 | 566 | ||
567 | if (gspca_dev->usb_err < 0) | ||
568 | return 0; | ||
543 | gspca_dev->usb_buf[1] = 0; | 569 | gspca_dev->usb_buf[1] = 0; |
544 | ret = usb_control_msg(gspca_dev->dev, | 570 | ret = usb_control_msg(gspca_dev->dev, |
545 | usb_rcvctrlpipe(gspca_dev->dev, 0), | 571 | usb_rcvctrlpipe(gspca_dev->dev, 0), |
@@ -550,62 +576,44 @@ static int reg_r_12(struct gspca_dev *gspca_dev, | |||
550 | gspca_dev->usb_buf, length, | 576 | gspca_dev->usb_buf, length, |
551 | 500); | 577 | 500); |
552 | if (ret < 0) { | 578 | if (ret < 0) { |
553 | PDEBUG(D_ERR, "reg_read err %d", ret); | 579 | PDEBUG(D_ERR, "reg_r_12 err %d", ret); |
554 | return -1; | 580 | gspca_dev->usb_err = ret; |
581 | return 0; | ||
555 | } | 582 | } |
556 | return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; | 583 | return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; |
557 | } | 584 | } |
558 | 585 | ||
559 | static int write_vector(struct gspca_dev *gspca_dev, | 586 | static void write_vector(struct gspca_dev *gspca_dev, |
560 | const struct cmd *data, int ncmds) | 587 | const struct cmd *data, int ncmds) |
561 | { | 588 | { |
562 | struct usb_device *dev = gspca_dev->dev; | ||
563 | int ret; | ||
564 | |||
565 | while (--ncmds >= 0) { | 589 | while (--ncmds >= 0) { |
566 | ret = reg_w_riv(dev, data->req, data->idx, data->val); | 590 | reg_w_riv(gspca_dev, data->req, data->idx, data->val); |
567 | if (ret < 0) { | ||
568 | PDEBUG(D_ERR, | ||
569 | "Register write failed for 0x%02x, 0x%04x, 0x%04x", | ||
570 | data->req, data->val, data->idx); | ||
571 | return ret; | ||
572 | } | ||
573 | data++; | 591 | data++; |
574 | } | 592 | } |
575 | return 0; | ||
576 | } | 593 | } |
577 | 594 | ||
578 | static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, | 595 | static void setup_qtable(struct gspca_dev *gspca_dev, |
579 | const u8 qtable[2][64]) | 596 | const u8 qtable[2][64]) |
580 | { | 597 | { |
581 | struct usb_device *dev = gspca_dev->dev; | 598 | int i; |
582 | int i, err; | ||
583 | 599 | ||
584 | /* loop over y components */ | 600 | /* loop over y components */ |
585 | for (i = 0; i < 64; i++) { | 601 | for (i = 0; i < 64; i++) |
586 | err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]); | 602 | reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]); |
587 | if (err < 0) | ||
588 | return err; | ||
589 | } | ||
590 | 603 | ||
591 | /* loop over c components */ | 604 | /* loop over c components */ |
592 | for (i = 0; i < 64; i++) { | 605 | for (i = 0; i < 64; i++) |
593 | err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]); | 606 | reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]); |
594 | if (err < 0) | ||
595 | return err; | ||
596 | } | ||
597 | return 0; | ||
598 | } | 607 | } |
599 | 608 | ||
600 | static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, | 609 | static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, |
601 | u8 req, u16 idx, u16 val) | 610 | u8 req, u16 idx, u16 val) |
602 | { | 611 | { |
603 | struct usb_device *dev = gspca_dev->dev; | 612 | u16 notdone; |
604 | int notdone; | ||
605 | 613 | ||
606 | reg_w_riv(dev, req, idx, val); | 614 | reg_w_riv(gspca_dev, req, idx, val); |
607 | notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 615 | notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); |
608 | reg_w_riv(dev, req, idx, val); | 616 | reg_w_riv(gspca_dev, req, idx, val); |
609 | 617 | ||
610 | PDEBUG(D_FRAM, "before wait 0x%04x", notdone); | 618 | PDEBUG(D_FRAM, "before wait 0x%04x", notdone); |
611 | 619 | ||
@@ -616,23 +624,22 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, | |||
616 | 624 | ||
617 | static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, | 625 | static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, |
618 | u8 req, | 626 | u8 req, |
619 | u16 idx, u16 val, u8 stat, u8 count) | 627 | u16 idx, u16 val, u16 endcode, u8 count) |
620 | { | 628 | { |
621 | struct usb_device *dev = gspca_dev->dev; | 629 | u16 status; |
622 | int status; | ||
623 | u8 endcode; | ||
624 | 630 | ||
625 | reg_w_riv(dev, req, idx, val); | 631 | reg_w_riv(gspca_dev, req, idx, val); |
626 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 632 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); |
627 | endcode = stat; | 633 | if (gspca_dev->usb_err < 0) |
628 | PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat); | 634 | return; |
635 | PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode); | ||
629 | if (!count) | 636 | if (!count) |
630 | return; | 637 | return; |
631 | count = 200; | 638 | count = 200; |
632 | while (--count > 0) { | 639 | while (--count > 0) { |
633 | msleep(10); | 640 | msleep(10); |
634 | /* gsmart mini2 write a each wait setting 1 ms is enough */ | 641 | /* gsmart mini2 write a each wait setting 1 ms is enough */ |
635 | /* reg_w_riv(dev, req, idx, val); */ | 642 | /* reg_w_riv(gspca_dev, req, idx, val); */ |
636 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 643 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); |
637 | if (status == endcode) { | 644 | if (status == endcode) { |
638 | PDEBUG(D_FRAM, "status 0x%04x after wait %d", | 645 | PDEBUG(D_FRAM, "status 0x%04x after wait %d", |
@@ -642,7 +649,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, | |||
642 | } | 649 | } |
643 | } | 650 | } |
644 | 651 | ||
645 | static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) | 652 | static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev) |
646 | { | 653 | { |
647 | int count = 10; | 654 | int count = 10; |
648 | 655 | ||
@@ -652,7 +659,6 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) | |||
652 | break; | 659 | break; |
653 | msleep(10); | 660 | msleep(10); |
654 | } | 661 | } |
655 | return gspca_dev->usb_buf[0]; | ||
656 | } | 662 | } |
657 | 663 | ||
658 | static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) | 664 | static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) |
@@ -686,28 +692,26 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) | |||
686 | static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) | 692 | static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) |
687 | { | 693 | { |
688 | struct sd *sd = (struct sd *) gspca_dev; | 694 | struct sd *sd = (struct sd *) gspca_dev; |
689 | struct usb_device *dev = gspca_dev->dev; | ||
690 | u8 Size; | 695 | u8 Size; |
691 | int rc; | ||
692 | 696 | ||
693 | Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | 697 | Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; |
694 | switch (sd->bridge) { | 698 | switch (sd->bridge) { |
695 | case BRIDGE_SPCA533: | 699 | case BRIDGE_SPCA533: |
696 | reg_w_riv(dev, 0x31, 0, 0); | 700 | reg_w_riv(gspca_dev, 0x31, 0, 0); |
697 | spca504B_WaitCmdStatus(gspca_dev); | 701 | spca504B_WaitCmdStatus(gspca_dev); |
698 | rc = spca504B_PollingDataReady(gspca_dev); | 702 | spca504B_PollingDataReady(gspca_dev); |
699 | spca50x_GetFirmware(gspca_dev); | 703 | spca50x_GetFirmware(gspca_dev); |
700 | reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ | 704 | reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ |
701 | reg_r(gspca_dev, 0x24, 8, 1); | 705 | reg_r(gspca_dev, 0x24, 8, 1); |
702 | 706 | ||
703 | reg_w_1(gspca_dev, 0x25, 0, 4, Size); | 707 | reg_w_1(gspca_dev, 0x25, 0, 4, Size); |
704 | reg_r(gspca_dev, 0x25, 4, 1); /* size */ | 708 | reg_r(gspca_dev, 0x25, 4, 1); /* size */ |
705 | rc = spca504B_PollingDataReady(gspca_dev); | 709 | spca504B_PollingDataReady(gspca_dev); |
706 | 710 | ||
707 | /* Init the cam width height with some values get on init ? */ | 711 | /* Init the cam width height with some values get on init ? */ |
708 | reg_w_riv(dev, 0x31, 0, 0x04); | 712 | reg_w_riv(gspca_dev, 0x31, 0, 0x04); |
709 | spca504B_WaitCmdStatus(gspca_dev); | 713 | spca504B_WaitCmdStatus(gspca_dev); |
710 | rc = spca504B_PollingDataReady(gspca_dev); | 714 | spca504B_PollingDataReady(gspca_dev); |
711 | break; | 715 | break; |
712 | default: | 716 | default: |
713 | /* case BRIDGE_SPCA504B: */ | 717 | /* case BRIDGE_SPCA504B: */ |
@@ -716,7 +720,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) | |||
716 | reg_r(gspca_dev, 0x25, 4, 1); /* size */ | 720 | reg_r(gspca_dev, 0x25, 4, 1); /* size */ |
717 | reg_w_1(gspca_dev, 0x27, 0, 0, 6); | 721 | reg_w_1(gspca_dev, 0x27, 0, 0, 6); |
718 | reg_r(gspca_dev, 0x27, 0, 1); /* type */ | 722 | reg_r(gspca_dev, 0x27, 0, 1); /* type */ |
719 | rc = spca504B_PollingDataReady(gspca_dev); | 723 | spca504B_PollingDataReady(gspca_dev); |
720 | break; | 724 | break; |
721 | case BRIDGE_SPCA504: | 725 | case BRIDGE_SPCA504: |
722 | Size += 3; | 726 | Size += 3; |
@@ -733,8 +737,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) | |||
733 | break; | 737 | break; |
734 | case BRIDGE_SPCA504C: | 738 | case BRIDGE_SPCA504C: |
735 | /* capture mode */ | 739 | /* capture mode */ |
736 | reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); | 740 | reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); |
737 | reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); | 741 | reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); |
738 | break; | 742 | break; |
739 | } | 743 | } |
740 | } | 744 | } |
@@ -762,37 +766,33 @@ static void spca504B_setQtable(struct gspca_dev *gspca_dev) | |||
762 | static void setbrightness(struct gspca_dev *gspca_dev) | 766 | static void setbrightness(struct gspca_dev *gspca_dev) |
763 | { | 767 | { |
764 | struct sd *sd = (struct sd *) gspca_dev; | 768 | struct sd *sd = (struct sd *) gspca_dev; |
765 | struct usb_device *dev = gspca_dev->dev; | ||
766 | u16 reg; | 769 | u16 reg; |
767 | 770 | ||
768 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; | 771 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; |
769 | reg_w_riv(dev, 0x00, reg, sd->brightness); | 772 | reg_w_riv(gspca_dev, 0x00, reg, sd->brightness); |
770 | } | 773 | } |
771 | 774 | ||
772 | static void setcontrast(struct gspca_dev *gspca_dev) | 775 | static void setcontrast(struct gspca_dev *gspca_dev) |
773 | { | 776 | { |
774 | struct sd *sd = (struct sd *) gspca_dev; | 777 | struct sd *sd = (struct sd *) gspca_dev; |
775 | struct usb_device *dev = gspca_dev->dev; | ||
776 | u16 reg; | 778 | u16 reg; |
777 | 779 | ||
778 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; | 780 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; |
779 | reg_w_riv(dev, 0x00, reg, sd->contrast); | 781 | reg_w_riv(gspca_dev, 0x00, reg, sd->contrast); |
780 | } | 782 | } |
781 | 783 | ||
782 | static void setcolors(struct gspca_dev *gspca_dev) | 784 | static void setcolors(struct gspca_dev *gspca_dev) |
783 | { | 785 | { |
784 | struct sd *sd = (struct sd *) gspca_dev; | 786 | struct sd *sd = (struct sd *) gspca_dev; |
785 | struct usb_device *dev = gspca_dev->dev; | ||
786 | u16 reg; | 787 | u16 reg; |
787 | 788 | ||
788 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; | 789 | reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; |
789 | reg_w_riv(dev, 0x00, reg, sd->colors); | 790 | reg_w_riv(gspca_dev, 0x00, reg, sd->colors); |
790 | } | 791 | } |
791 | 792 | ||
792 | static void init_ctl_reg(struct gspca_dev *gspca_dev) | 793 | static void init_ctl_reg(struct gspca_dev *gspca_dev) |
793 | { | 794 | { |
794 | struct sd *sd = (struct sd *) gspca_dev; | 795 | struct sd *sd = (struct sd *) gspca_dev; |
795 | struct usb_device *dev = gspca_dev->dev; | ||
796 | int pollreg = 1; | 796 | int pollreg = 1; |
797 | 797 | ||
798 | setbrightness(gspca_dev); | 798 | setbrightness(gspca_dev); |
@@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) | |||
807 | default: | 807 | default: |
808 | /* case BRIDGE_SPCA533: */ | 808 | /* case BRIDGE_SPCA533: */ |
809 | /* case BRIDGE_SPCA504B: */ | 809 | /* case BRIDGE_SPCA504B: */ |
810 | reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */ | 810 | reg_w_riv(gspca_dev, 0, 0x00, 0x21ad); /* hue */ |
811 | reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */ | 811 | reg_w_riv(gspca_dev, 0, 0x01, 0x21ac); /* sat/hue */ |
812 | reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */ | 812 | reg_w_riv(gspca_dev, 0, 0x00, 0x21a3); /* gamma */ |
813 | break; | 813 | break; |
814 | case BRIDGE_SPCA536: | 814 | case BRIDGE_SPCA536: |
815 | reg_w_riv(dev, 0, 0x40, 0x20f5); | 815 | reg_w_riv(gspca_dev, 0, 0x40, 0x20f5); |
816 | reg_w_riv(dev, 0, 0x01, 0x20f4); | 816 | reg_w_riv(gspca_dev, 0, 0x01, 0x20f4); |
817 | reg_w_riv(dev, 0, 0x00, 0x2089); | 817 | reg_w_riv(gspca_dev, 0, 0x00, 0x2089); |
818 | break; | 818 | break; |
819 | } | 819 | } |
820 | if (pollreg) | 820 | if (pollreg) |
@@ -881,18 +881,17 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
881 | static int sd_init(struct gspca_dev *gspca_dev) | 881 | static int sd_init(struct gspca_dev *gspca_dev) |
882 | { | 882 | { |
883 | struct sd *sd = (struct sd *) gspca_dev; | 883 | struct sd *sd = (struct sd *) gspca_dev; |
884 | struct usb_device *dev = gspca_dev->dev; | 884 | int i; |
885 | int i, err_code; | ||
886 | u8 info[6]; | 885 | u8 info[6]; |
887 | 886 | ||
888 | switch (sd->bridge) { | 887 | switch (sd->bridge) { |
889 | case BRIDGE_SPCA504B: | 888 | case BRIDGE_SPCA504B: |
890 | reg_w_riv(dev, 0x1d, 0x00, 0); | 889 | reg_w_riv(gspca_dev, 0x1d, 0x00, 0); |
891 | reg_w_riv(dev, 0, 0x01, 0x2306); | 890 | reg_w_riv(gspca_dev, 0, 0x01, 0x2306); |
892 | reg_w_riv(dev, 0, 0x00, 0x0d04); | 891 | reg_w_riv(gspca_dev, 0, 0x00, 0x0d04); |
893 | reg_w_riv(dev, 0, 0x00, 0x2000); | 892 | reg_w_riv(gspca_dev, 0, 0x00, 0x2000); |
894 | reg_w_riv(dev, 0, 0x13, 0x2301); | 893 | reg_w_riv(gspca_dev, 0, 0x13, 0x2301); |
895 | reg_w_riv(dev, 0, 0x00, 0x2306); | 894 | reg_w_riv(gspca_dev, 0, 0x00, 0x2306); |
896 | /* fall thru */ | 895 | /* fall thru */ |
897 | case BRIDGE_SPCA533: | 896 | case BRIDGE_SPCA533: |
898 | spca504B_PollingDataReady(gspca_dev); | 897 | spca504B_PollingDataReady(gspca_dev); |
@@ -904,13 +903,13 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
904 | reg_w_1(gspca_dev, 0x24, 0, 0, 0); | 903 | reg_w_1(gspca_dev, 0x24, 0, 0, 0); |
905 | reg_r(gspca_dev, 0x24, 0, 1); | 904 | reg_r(gspca_dev, 0x24, 0, 1); |
906 | spca504B_PollingDataReady(gspca_dev); | 905 | spca504B_PollingDataReady(gspca_dev); |
907 | reg_w_riv(dev, 0x34, 0, 0); | 906 | reg_w_riv(gspca_dev, 0x34, 0, 0); |
908 | spca504B_WaitCmdStatus(gspca_dev); | 907 | spca504B_WaitCmdStatus(gspca_dev); |
909 | break; | 908 | break; |
910 | case BRIDGE_SPCA504C: /* pccam600 */ | 909 | case BRIDGE_SPCA504C: /* pccam600 */ |
911 | PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); | 910 | PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); |
912 | reg_w_riv(dev, 0xe0, 0x0000, 0x0000); | 911 | reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000); |
913 | reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */ | 912 | reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */ |
914 | spca504_wait_status(gspca_dev); | 913 | spca504_wait_status(gspca_dev); |
915 | if (sd->subtype == LogitechClickSmart420) | 914 | if (sd->subtype == LogitechClickSmart420) |
916 | write_vector(gspca_dev, | 915 | write_vector(gspca_dev, |
@@ -919,12 +918,7 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
919 | else | 918 | else |
920 | write_vector(gspca_dev, spca504_pccam600_open_data, | 919 | write_vector(gspca_dev, spca504_pccam600_open_data, |
921 | ARRAY_SIZE(spca504_pccam600_open_data)); | 920 | ARRAY_SIZE(spca504_pccam600_open_data)); |
922 | err_code = spca50x_setup_qtable(gspca_dev, | 921 | setup_qtable(gspca_dev, qtable_creative_pccam); |
923 | qtable_creative_pccam); | ||
924 | if (err_code < 0) { | ||
925 | PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed"); | ||
926 | return err_code; | ||
927 | } | ||
928 | break; | 922 | break; |
929 | default: | 923 | default: |
930 | /* case BRIDGE_SPCA504: */ | 924 | /* case BRIDGE_SPCA504: */ |
@@ -958,29 +952,24 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
958 | 6, 0, 0x86, 1); */ | 952 | 6, 0, 0x86, 1); */ |
959 | /* spca504A_acknowledged_command (gspca_dev, 0x24, | 953 | /* spca504A_acknowledged_command (gspca_dev, 0x24, |
960 | 0, 0, 0x9D, 1); */ | 954 | 0, 0, 0x9D, 1); */ |
961 | reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ | 955 | reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); |
962 | reg_w_riv(dev, 0x00, 0x2310, 0x05); | 956 | /* L92 sno1t.txt */ |
957 | reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); | ||
963 | spca504A_acknowledged_command(gspca_dev, 0x01, | 958 | spca504A_acknowledged_command(gspca_dev, 0x01, |
964 | 0x0f, 0, 0xff, 0); | 959 | 0x0f, 0, 0xff, 0); |
965 | } | 960 | } |
966 | /* setup qtable */ | 961 | /* setup qtable */ |
967 | reg_w_riv(dev, 0, 0x2000, 0); | 962 | reg_w_riv(gspca_dev, 0, 0x2000, 0); |
968 | reg_w_riv(dev, 0, 0x2883, 1); | 963 | reg_w_riv(gspca_dev, 0, 0x2883, 1); |
969 | err_code = spca50x_setup_qtable(gspca_dev, | 964 | setup_qtable(gspca_dev, qtable_spca504_default); |
970 | qtable_spca504_default); | ||
971 | if (err_code < 0) { | ||
972 | PDEBUG(D_ERR, "spca50x_setup_qtable failed"); | ||
973 | return err_code; | ||
974 | } | ||
975 | break; | 965 | break; |
976 | } | 966 | } |
977 | return 0; | 967 | return gspca_dev->usb_err; |
978 | } | 968 | } |
979 | 969 | ||
980 | static int sd_start(struct gspca_dev *gspca_dev) | 970 | static int sd_start(struct gspca_dev *gspca_dev) |
981 | { | 971 | { |
982 | struct sd *sd = (struct sd *) gspca_dev; | 972 | struct sd *sd = (struct sd *) gspca_dev; |
983 | struct usb_device *dev = gspca_dev->dev; | ||
984 | int enable; | 973 | int enable; |
985 | int i; | 974 | int i; |
986 | u8 info[6]; | 975 | u8 info[6]; |
@@ -1005,13 +994,13 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
1005 | case MegapixV4: | 994 | case MegapixV4: |
1006 | case LogitechClickSmart820: | 995 | case LogitechClickSmart820: |
1007 | case MegaImageVI: | 996 | case MegaImageVI: |
1008 | reg_w_riv(dev, 0xf0, 0, 0); | 997 | reg_w_riv(gspca_dev, 0xf0, 0, 0); |
1009 | spca504B_WaitCmdStatus(gspca_dev); | 998 | spca504B_WaitCmdStatus(gspca_dev); |
1010 | reg_r(gspca_dev, 0xf0, 4, 0); | 999 | reg_r(gspca_dev, 0xf0, 4, 0); |
1011 | spca504B_WaitCmdStatus(gspca_dev); | 1000 | spca504B_WaitCmdStatus(gspca_dev); |
1012 | break; | 1001 | break; |
1013 | default: | 1002 | default: |
1014 | reg_w_riv(dev, 0x31, 0, 0x04); | 1003 | reg_w_riv(gspca_dev, 0x31, 0, 0x04); |
1015 | spca504B_WaitCmdStatus(gspca_dev); | 1004 | spca504B_WaitCmdStatus(gspca_dev); |
1016 | spca504B_PollingDataReady(gspca_dev); | 1005 | spca504B_PollingDataReady(gspca_dev); |
1017 | break; | 1006 | break; |
@@ -1048,8 +1037,9 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
1048 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); | 1037 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); |
1049 | } | 1038 | } |
1050 | spca504B_SetSizeType(gspca_dev); | 1039 | spca504B_SetSizeType(gspca_dev); |
1051 | reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ | 1040 | reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); |
1052 | reg_w_riv(dev, 0x00, 0x2310, 0x05); | 1041 | /* L92 sno1t.txt */ |
1042 | reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); | ||
1053 | break; | 1043 | break; |
1054 | case BRIDGE_SPCA504C: | 1044 | case BRIDGE_SPCA504C: |
1055 | if (sd->subtype == LogitechClickSmart420) { | 1045 | if (sd->subtype == LogitechClickSmart420) { |
@@ -1061,36 +1051,37 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
1061 | ARRAY_SIZE(spca504_pccam600_init_data)); | 1051 | ARRAY_SIZE(spca504_pccam600_init_data)); |
1062 | } | 1052 | } |
1063 | enable = (sd->autogain ? 0x04 : 0x01); | 1053 | enable = (sd->autogain ? 0x04 : 0x01); |
1064 | reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */ | 1054 | reg_w_riv(gspca_dev, 0x0c, 0x0000, enable); |
1065 | reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */ | 1055 | /* auto exposure */ |
1056 | reg_w_riv(gspca_dev, 0xb0, 0x0000, enable); | ||
1057 | /* auto whiteness */ | ||
1066 | 1058 | ||
1067 | /* set default exposure compensation and whiteness balance */ | 1059 | /* set default exposure compensation and whiteness balance */ |
1068 | reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */ | 1060 | reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */ |
1069 | reg_w_riv(dev, 0x30, 0x0002, 1600); | 1061 | reg_w_riv(gspca_dev, 0x30, 0x0002, 1600); |
1070 | spca504B_SetSizeType(gspca_dev); | 1062 | spca504B_SetSizeType(gspca_dev); |
1071 | break; | 1063 | break; |
1072 | } | 1064 | } |
1073 | init_ctl_reg(gspca_dev); | 1065 | init_ctl_reg(gspca_dev); |
1074 | return 0; | 1066 | return gspca_dev->usb_err; |
1075 | } | 1067 | } |
1076 | 1068 | ||
1077 | static void sd_stopN(struct gspca_dev *gspca_dev) | 1069 | static void sd_stopN(struct gspca_dev *gspca_dev) |
1078 | { | 1070 | { |
1079 | struct sd *sd = (struct sd *) gspca_dev; | 1071 | struct sd *sd = (struct sd *) gspca_dev; |
1080 | struct usb_device *dev = gspca_dev->dev; | ||
1081 | 1072 | ||
1082 | switch (sd->bridge) { | 1073 | switch (sd->bridge) { |
1083 | default: | 1074 | default: |
1084 | /* case BRIDGE_SPCA533: */ | 1075 | /* case BRIDGE_SPCA533: */ |
1085 | /* case BRIDGE_SPCA536: */ | 1076 | /* case BRIDGE_SPCA536: */ |
1086 | /* case BRIDGE_SPCA504B: */ | 1077 | /* case BRIDGE_SPCA504B: */ |
1087 | reg_w_riv(dev, 0x31, 0, 0); | 1078 | reg_w_riv(gspca_dev, 0x31, 0, 0); |
1088 | spca504B_WaitCmdStatus(gspca_dev); | 1079 | spca504B_WaitCmdStatus(gspca_dev); |
1089 | spca504B_PollingDataReady(gspca_dev); | 1080 | spca504B_PollingDataReady(gspca_dev); |
1090 | break; | 1081 | break; |
1091 | case BRIDGE_SPCA504: | 1082 | case BRIDGE_SPCA504: |
1092 | case BRIDGE_SPCA504C: | 1083 | case BRIDGE_SPCA504C: |
1093 | reg_w_riv(dev, 0x00, 0x2000, 0x0000); | 1084 | reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000); |
1094 | 1085 | ||
1095 | if (sd->subtype == AiptekMiniPenCam13) { | 1086 | if (sd->subtype == AiptekMiniPenCam13) { |
1096 | /* spca504a aiptek */ | 1087 | /* spca504a aiptek */ |
@@ -1102,7 +1093,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
1102 | 0x0f, 0x00, 0xff, 1); | 1093 | 0x0f, 0x00, 0xff, 1); |
1103 | } else { | 1094 | } else { |
1104 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); | 1095 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); |
1105 | reg_w_riv(dev, 0x01, 0x000f, 0x0000); | 1096 | reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000); |
1106 | } | 1097 | } |
1107 | break; | 1098 | break; |
1108 | } | 1099 | } |
@@ -1216,7 +1207,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |||
1216 | sd->brightness = val; | 1207 | sd->brightness = val; |
1217 | if (gspca_dev->streaming) | 1208 | if (gspca_dev->streaming) |
1218 | setbrightness(gspca_dev); | 1209 | setbrightness(gspca_dev); |
1219 | return 0; | 1210 | return gspca_dev->usb_err; |
1220 | } | 1211 | } |
1221 | 1212 | ||
1222 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | 1213 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1234,7 +1225,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |||
1234 | sd->contrast = val; | 1225 | sd->contrast = val; |
1235 | if (gspca_dev->streaming) | 1226 | if (gspca_dev->streaming) |
1236 | setcontrast(gspca_dev); | 1227 | setcontrast(gspca_dev); |
1237 | return 0; | 1228 | return gspca_dev->usb_err; |
1238 | } | 1229 | } |
1239 | 1230 | ||
1240 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | 1231 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1252,7 +1243,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) | |||
1252 | sd->colors = val; | 1243 | sd->colors = val; |
1253 | if (gspca_dev->streaming) | 1244 | if (gspca_dev->streaming) |
1254 | setcolors(gspca_dev); | 1245 | setcolors(gspca_dev); |
1255 | return 0; | 1246 | return gspca_dev->usb_err; |
1256 | } | 1247 | } |
1257 | 1248 | ||
1258 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | 1249 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1292,7 +1283,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, | |||
1292 | sd->quality = jcomp->quality; | 1283 | sd->quality = jcomp->quality; |
1293 | if (gspca_dev->streaming) | 1284 | if (gspca_dev->streaming) |
1294 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | 1285 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); |
1295 | return 0; | 1286 | return gspca_dev->usb_err; |
1296 | } | 1287 | } |
1297 | 1288 | ||
1298 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | 1289 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, |
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 69e5dc4fc9de..1a800fc1c00e 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c | |||
@@ -5345,9 +5345,6 @@ static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */ | |||
5345 | {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, | 5345 | {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, |
5346 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, | 5346 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, |
5347 | {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, | 5347 | {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, |
5348 | {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, | ||
5349 | {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, | ||
5350 | |||
5351 | {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, | 5348 | {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, |
5352 | {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, | 5349 | {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, |
5353 | {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, | 5350 | {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, |
@@ -5364,27 +5361,27 @@ static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */ | |||
5364 | {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, | 5361 | {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, |
5365 | {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, | 5362 | {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, |
5366 | {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, | 5363 | {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, |
5367 | {0xa0, 0x95, ZC3XX_R18D_YTARGET}, | 5364 | {0xa0, 0x70, ZC3XX_R18D_YTARGET}, |
5368 | {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, | 5365 | {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, |
5369 | {0xa0, 0x00, 0x01ad}, | 5366 | {0xa0, 0x00, 0x01ad}, |
5370 | {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, | 5367 | {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, |
5371 | {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, | 5368 | {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, |
5372 | {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, | 5369 | {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, |
5373 | {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, | 5370 | {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, |
5371 | {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, | ||
5372 | {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, | ||
5374 | {} | 5373 | {} |
5375 | }; | 5374 | }; |
5376 | static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */ | 5375 | static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */ |
5377 | {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, | 5376 | {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, |
5378 | {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, | 5377 | {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, |
5379 | {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, | 5378 | {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, |
5380 | {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, | 5379 | {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, |
5381 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, | 5380 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, |
5382 | {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, | 5381 | {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, |
5383 | {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, | 5382 | {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, |
5384 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, | 5383 | {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, |
5385 | {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, | 5384 | {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, |
5386 | {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, | ||
5387 | {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, | ||
5388 | {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, | 5385 | {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, |
5389 | {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, | 5386 | {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, |
5390 | {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, | 5387 | {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, |
@@ -5400,13 +5397,15 @@ static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */ | |||
5400 | {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, | 5397 | {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, |
5401 | {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, | 5398 | {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, |
5402 | {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, | 5399 | {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, |
5403 | {0xa0, 0x95, ZC3XX_R18D_YTARGET}, | 5400 | {0xa0, 0x70, ZC3XX_R18D_YTARGET}, |
5404 | {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, | 5401 | {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, |
5405 | {0xa0, 0x00, 0x01ad}, | 5402 | {0xa0, 0x00, 0x01ad}, |
5406 | {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, | 5403 | {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, |
5407 | {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, | 5404 | {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, |
5408 | {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, | 5405 | {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, |
5409 | {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, | 5406 | {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, |
5407 | {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, | ||
5408 | {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, | ||
5410 | {} | 5409 | {} |
5411 | }; | 5410 | }; |
5412 | static const struct usb_action tas5130cxx_50HZ[] = { | 5411 | static const struct usb_action tas5130cxx_50HZ[] = { |
@@ -6424,11 +6423,11 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev) | |||
6424 | if (retword != 0) | 6423 | if (retword != 0) |
6425 | return 0x0e; /* PAS202BCB */ | 6424 | return 0x0e; /* PAS202BCB */ |
6426 | 6425 | ||
6427 | start_2wr_probe(dev, 0x02); /* ?? */ | 6426 | start_2wr_probe(dev, 0x02); /* TAS5130C */ |
6428 | i2c_write(gspca_dev, 0x01, 0xaa, 0x00); | 6427 | i2c_write(gspca_dev, 0x01, 0xaa, 0x00); |
6429 | retword = i2c_read(gspca_dev, 0x01); | 6428 | retword = i2c_read(gspca_dev, 0x01); |
6430 | if (retword != 0) | 6429 | if (retword != 0) |
6431 | return 0x02; /* ?? */ | 6430 | return 0x02; /* TAS5130C */ |
6432 | ov_check: | 6431 | ov_check: |
6433 | reg_r(gspca_dev, 0x0010); /* ?? */ | 6432 | reg_r(gspca_dev, 0x0010); /* ?? */ |
6434 | reg_r(gspca_dev, 0x0010); | 6433 | reg_r(gspca_dev, 0x0010); |
@@ -6505,6 +6504,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) | |||
6505 | reg_r(gspca_dev, 0x0010); | 6504 | reg_r(gspca_dev, 0x0010); |
6506 | /* value 0x4001 is meaningless */ | 6505 | /* value 0x4001 is meaningless */ |
6507 | if (retword != 0x4001) { | 6506 | if (retword != 0x4001) { |
6507 | if ((retword & 0xff00) == 0x6400) | ||
6508 | return 0x02; /* TAS5130C */ | ||
6508 | for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { | 6509 | for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { |
6509 | if (chipset_revision_sensor[i].revision == retword) { | 6510 | if (chipset_revision_sensor[i].revision == retword) { |
6510 | sd->chip_revision = retword; | 6511 | sd->chip_revision = retword; |
@@ -6515,7 +6516,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) | |||
6515 | } | 6516 | } |
6516 | } | 6517 | } |
6517 | 6518 | ||
6518 | reg_w(dev, 0x01, 0x0000); /* check ?? */ | 6519 | reg_w(dev, 0x01, 0x0000); /* check PB0330 */ |
6519 | reg_w(dev, 0x01, 0x0001); | 6520 | reg_w(dev, 0x01, 0x0001); |
6520 | reg_w(dev, 0xdd, 0x008b); | 6521 | reg_w(dev, 0xdd, 0x008b); |
6521 | reg_w(dev, 0x0a, 0x0010); | 6522 | reg_w(dev, 0x0a, 0x0010); |
@@ -6524,7 +6525,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) | |||
6524 | retword = i2c_read(gspca_dev, 0x00); | 6525 | retword = i2c_read(gspca_dev, 0x00); |
6525 | if (retword != 0) { | 6526 | if (retword != 0) { |
6526 | PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); | 6527 | PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); |
6527 | return 0x0a; /* ?? */ | 6528 | return 0x0a; /* PB0330 */ |
6528 | } | 6529 | } |
6529 | 6530 | ||
6530 | reg_w(dev, 0x01, 0x0000); | 6531 | reg_w(dev, 0x01, 0x0000); |
@@ -6673,6 +6674,10 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
6673 | PDEBUG(D_PROBE, "Find Sensor HV7131B"); | 6674 | PDEBUG(D_PROBE, "Find Sensor HV7131B"); |
6674 | sd->sensor = SENSOR_HV7131B; | 6675 | sd->sensor = SENSOR_HV7131B; |
6675 | break; | 6676 | break; |
6677 | case 0x02: | ||
6678 | PDEBUG(D_PROBE, "Sensor TAS5130C"); | ||
6679 | sd->sensor = SENSOR_TAS5130CXX; | ||
6680 | break; | ||
6676 | case 0x04: | 6681 | case 0x04: |
6677 | PDEBUG(D_PROBE, "Find Sensor CS2102"); | 6682 | PDEBUG(D_PROBE, "Find Sensor CS2102"); |
6678 | sd->sensor = SENSOR_CS2102; | 6683 | sd->sensor = SENSOR_CS2102; |
@@ -6866,11 +6871,14 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6866 | case SENSOR_GC0305: | 6871 | case SENSOR_GC0305: |
6867 | case SENSOR_OV7620: | 6872 | case SENSOR_OV7620: |
6868 | case SENSOR_PO2030: | 6873 | case SENSOR_PO2030: |
6874 | case SENSOR_TAS5130CXX: | ||
6869 | case SENSOR_TAS5130C_VF0250: | 6875 | case SENSOR_TAS5130C_VF0250: |
6870 | /* msleep(100); * ?? */ | 6876 | /* msleep(100); * ?? */ |
6871 | reg_r(gspca_dev, 0x0002); /* --> 0x40 */ | 6877 | reg_r(gspca_dev, 0x0002); /* --> 0x40 */ |
6872 | reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ | 6878 | reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ |
6873 | reg_w(dev, 0x15, 0x01ae); | 6879 | reg_w(dev, 0x15, 0x01ae); |
6880 | if (sd->sensor == SENSOR_TAS5130CXX) | ||
6881 | break; | ||
6874 | reg_w(dev, 0x0d, 0x003a); | 6882 | reg_w(dev, 0x0d, 0x003a); |
6875 | reg_w(dev, 0x02, 0x003b); | 6883 | reg_w(dev, 0x02, 0x003b); |
6876 | reg_w(dev, 0x00, 0x0038); | 6884 | reg_w(dev, 0x00, 0x0038); |
@@ -6887,6 +6895,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6887 | break; | 6895 | break; |
6888 | case SENSOR_PAS202B: | 6896 | case SENSOR_PAS202B: |
6889 | case SENSOR_GC0305: | 6897 | case SENSOR_GC0305: |
6898 | case SENSOR_TAS5130CXX: | ||
6890 | reg_r(gspca_dev, 0x0008); | 6899 | reg_r(gspca_dev, 0x0008); |
6891 | /* fall thru */ | 6900 | /* fall thru */ |
6892 | case SENSOR_PO2030: | 6901 | case SENSOR_PO2030: |
@@ -6928,6 +6937,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
6928 | reg_w(dev, 0x40, 0x0117); | 6937 | reg_w(dev, 0x40, 0x0117); |
6929 | break; | 6938 | break; |
6930 | case SENSOR_GC0305: | 6939 | case SENSOR_GC0305: |
6940 | case SENSOR_TAS5130CXX: | ||
6931 | reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ | 6941 | reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ |
6932 | reg_w(dev, 0x15, 0x01ae); | 6942 | reg_w(dev, 0x15, 0x01ae); |
6933 | /* fall thru */ | 6943 | /* fall thru */ |
@@ -7220,7 +7230,7 @@ static const __devinitdata struct usb_device_id device_table[] = { | |||
7220 | {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106}, | 7230 | {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106}, |
7221 | {USB_DEVICE(0x0ac8, 0x301b)}, | 7231 | {USB_DEVICE(0x0ac8, 0x301b)}, |
7222 | {USB_DEVICE(0x0ac8, 0x303b)}, | 7232 | {USB_DEVICE(0x0ac8, 0x303b)}, |
7223 | {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, | 7233 | {USB_DEVICE(0x0ac8, 0x305b)}, |
7224 | {USB_DEVICE(0x0ac8, 0x307b)}, | 7234 | {USB_DEVICE(0x0ac8, 0x307b)}, |
7225 | {USB_DEVICE(0x10fd, 0x0128)}, | 7235 | {USB_DEVICE(0x10fd, 0x0128)}, |
7226 | {USB_DEVICE(0x10fd, 0x804d)}, | 7236 | {USB_DEVICE(0x10fd, 0x804d)}, |
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index 1c9bc94c905c..51f393d03a46 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c | |||
@@ -145,7 +145,7 @@ static int device_authorization(struct hdpvr_device *dev) | |||
145 | #ifdef HDPVR_DEBUG | 145 | #ifdef HDPVR_DEBUG |
146 | else { | 146 | else { |
147 | hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, | 147 | hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, |
148 | sizeof(print_buf), 0); | 148 | 5*buf_size+1, 0); |
149 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, | 149 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, |
150 | "Status request returned, len %d: %s\n", | 150 | "Status request returned, len %d: %s\n", |
151 | ret, print_buf); | 151 | ret, print_buf); |
@@ -168,13 +168,13 @@ static int device_authorization(struct hdpvr_device *dev) | |||
168 | 168 | ||
169 | response = dev->usbc_buf+38; | 169 | response = dev->usbc_buf+38; |
170 | #ifdef HDPVR_DEBUG | 170 | #ifdef HDPVR_DEBUG |
171 | hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0); | 171 | hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); |
172 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", | 172 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", |
173 | print_buf); | 173 | print_buf); |
174 | #endif | 174 | #endif |
175 | challenge(response); | 175 | challenge(response); |
176 | #ifdef HDPVR_DEBUG | 176 | #ifdef HDPVR_DEBUG |
177 | hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0); | 177 | hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); |
178 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", | 178 | v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", |
179 | print_buf); | 179 | print_buf); |
180 | #endif | 180 | #endif |
@@ -376,8 +376,8 @@ static int hdpvr_probe(struct usb_interface *interface, | |||
376 | usb_set_intfdata(interface, dev); | 376 | usb_set_intfdata(interface, dev); |
377 | 377 | ||
378 | /* let the user know what node this device is now attached to */ | 378 | /* let the user know what node this device is now attached to */ |
379 | v4l2_info(&dev->v4l2_dev, "device now attached to /dev/video%d\n", | 379 | v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", |
380 | dev->video_dev->minor); | 380 | video_device_node_name(dev->video_dev)); |
381 | return 0; | 381 | return 0; |
382 | 382 | ||
383 | error: | 383 | error: |
@@ -391,13 +391,10 @@ error: | |||
391 | static void hdpvr_disconnect(struct usb_interface *interface) | 391 | static void hdpvr_disconnect(struct usb_interface *interface) |
392 | { | 392 | { |
393 | struct hdpvr_device *dev; | 393 | struct hdpvr_device *dev; |
394 | int minor; | ||
395 | 394 | ||
396 | dev = usb_get_intfdata(interface); | 395 | dev = usb_get_intfdata(interface); |
397 | usb_set_intfdata(interface, NULL); | 396 | usb_set_intfdata(interface, NULL); |
398 | 397 | ||
399 | minor = dev->video_dev->minor; | ||
400 | |||
401 | /* prevent more I/O from starting and stop any ongoing */ | 398 | /* prevent more I/O from starting and stop any ongoing */ |
402 | mutex_lock(&dev->io_mutex); | 399 | mutex_lock(&dev->io_mutex); |
403 | dev->status = STATUS_DISCONNECTED; | 400 | dev->status = STATUS_DISCONNECTED; |
@@ -425,7 +422,8 @@ static void hdpvr_disconnect(struct usb_interface *interface) | |||
425 | 422 | ||
426 | atomic_dec(&dev_nr); | 423 | atomic_dec(&dev_nr); |
427 | 424 | ||
428 | v4l2_info(&dev->v4l2_dev, "device /dev/video%d disconnected\n", minor); | 425 | v4l2_info(&dev->v4l2_dev, "device %s disconnected\n", |
426 | video_device_node_name(dev->video_dev)); | ||
429 | 427 | ||
430 | v4l2_device_unregister(&dev->v4l2_dev); | 428 | v4l2_device_unregister(&dev->v4l2_dev); |
431 | kfree(dev->usbc_buf); | 429 | kfree(dev->usbc_buf); |
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index b5439cabb381..fdd782039e9d 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c | |||
@@ -523,7 +523,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) | |||
523 | 523 | ||
524 | mutex_lock(&dev->io_mutex); | 524 | mutex_lock(&dev->io_mutex); |
525 | 525 | ||
526 | if (video_is_unregistered(dev->video_dev)) { | 526 | if (!video_is_registered(dev->video_dev)) { |
527 | mutex_unlock(&dev->io_mutex); | 527 | mutex_unlock(&dev->io_mutex); |
528 | return -EIO; | 528 | return -EIO; |
529 | } | 529 | } |
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 64360d26b32d..b86e35386cee 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c | |||
@@ -353,6 +353,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
353 | ir_type = IR_TYPE_RC5; | 353 | ir_type = IR_TYPE_RC5; |
354 | ir_codes = &ir_codes_fusionhdtv_mce_table; | 354 | ir_codes = &ir_codes_fusionhdtv_mce_table; |
355 | break; | 355 | break; |
356 | case 0x0b: | ||
356 | case 0x47: | 357 | case 0x47: |
357 | case 0x71: | 358 | case 0x71: |
358 | if (adap->id == I2C_HW_B_CX2388x || | 359 | if (adap->id == I2C_HW_B_CX2388x || |
@@ -422,7 +423,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
422 | 423 | ||
423 | /* Make sure we are all setup before going on */ | 424 | /* Make sure we are all setup before going on */ |
424 | if (!name || !ir->get_key || !ir_type || !ir_codes) { | 425 | if (!name || !ir->get_key || !ir_type || !ir_codes) { |
425 | dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n", | 426 | dprintk(1, ": Unsupported device at address 0x%02x\n", |
426 | addr); | 427 | addr); |
427 | err = -ENODEV; | 428 | err = -ENODEV; |
428 | goto err_out_free; | 429 | goto err_out_free; |
@@ -437,7 +438,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
437 | dev_name(&client->dev)); | 438 | dev_name(&client->dev)); |
438 | 439 | ||
439 | /* init + register input device */ | 440 | /* init + register input device */ |
440 | err = ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); | 441 | err = ir_input_init(input_dev, &ir->ir, ir_type); |
441 | if (err < 0) | 442 | if (err < 0) |
442 | goto err_out_free; | 443 | goto err_out_free; |
443 | 444 | ||
@@ -445,7 +446,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
445 | input_dev->name = ir->name; | 446 | input_dev->name = ir->name; |
446 | input_dev->phys = ir->phys; | 447 | input_dev->phys = ir->phys; |
447 | 448 | ||
448 | err = input_register_device(ir->input); | 449 | err = ir_input_register(ir->input, ir->ir_codes); |
449 | if (err) | 450 | if (err) |
450 | goto err_out_free; | 451 | goto err_out_free; |
451 | 452 | ||
@@ -459,8 +460,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
459 | return 0; | 460 | return 0; |
460 | 461 | ||
461 | err_out_free: | 462 | err_out_free: |
462 | ir_input_free(input_dev); | ||
463 | input_free_device(input_dev); | ||
464 | kfree(ir); | 463 | kfree(ir); |
465 | return err; | 464 | return err; |
466 | } | 465 | } |
@@ -473,8 +472,7 @@ static int ir_remove(struct i2c_client *client) | |||
473 | cancel_delayed_work_sync(&ir->work); | 472 | cancel_delayed_work_sync(&ir->work); |
474 | 473 | ||
475 | /* unregister device */ | 474 | /* unregister device */ |
476 | ir_input_free(ir->input); | 475 | ir_input_unregister(ir->input); |
477 | input_unregister_device(ir->input); | ||
478 | 476 | ||
479 | /* free memory */ | 477 | /* free memory */ |
480 | kfree(ir); | 478 | kfree(ir); |
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index e707ef3086b2..babcabd73c08 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
@@ -985,8 +985,8 @@ int ivtv_v4l2_open(struct file *filp) | |||
985 | 985 | ||
986 | mutex_lock(&itv->serialize_lock); | 986 | mutex_lock(&itv->serialize_lock); |
987 | if (ivtv_init_on_first_open(itv)) { | 987 | if (ivtv_init_on_first_open(itv)) { |
988 | IVTV_ERR("Failed to initialize on minor %d\n", | 988 | IVTV_ERR("Failed to initialize on device %s\n", |
989 | vdev->minor); | 989 | video_device_node_name(vdev)); |
990 | mutex_unlock(&itv->serialize_lock); | 990 | mutex_unlock(&itv->serialize_lock); |
991 | return -ENXIO; | 991 | return -ENXIO; |
992 | } | 992 | } |
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 67699e3f2aaa..e12c6022373e 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -245,6 +245,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
245 | { | 245 | { |
246 | struct ivtv_stream *s = &itv->streams[type]; | 246 | struct ivtv_stream *s = &itv->streams[type]; |
247 | int vfl_type = ivtv_stream_info[type].vfl_type; | 247 | int vfl_type = ivtv_stream_info[type].vfl_type; |
248 | const char *name; | ||
248 | int num; | 249 | int num; |
249 | 250 | ||
250 | if (s->vdev == NULL) | 251 | if (s->vdev == NULL) |
@@ -268,24 +269,24 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
268 | s->vdev = NULL; | 269 | s->vdev = NULL; |
269 | return -ENOMEM; | 270 | return -ENOMEM; |
270 | } | 271 | } |
271 | num = s->vdev->num; | 272 | name = video_device_node_name(s->vdev); |
272 | 273 | ||
273 | switch (vfl_type) { | 274 | switch (vfl_type) { |
274 | case VFL_TYPE_GRABBER: | 275 | case VFL_TYPE_GRABBER: |
275 | IVTV_INFO("Registered device video%d for %s (%d kB)\n", | 276 | IVTV_INFO("Registered device %s for %s (%d kB)\n", |
276 | num, s->name, itv->options.kilobytes[type]); | 277 | name, s->name, itv->options.kilobytes[type]); |
277 | break; | 278 | break; |
278 | case VFL_TYPE_RADIO: | 279 | case VFL_TYPE_RADIO: |
279 | IVTV_INFO("Registered device radio%d for %s\n", | 280 | IVTV_INFO("Registered device %s for %s\n", |
280 | num, s->name); | 281 | name, s->name); |
281 | break; | 282 | break; |
282 | case VFL_TYPE_VBI: | 283 | case VFL_TYPE_VBI: |
283 | if (itv->options.kilobytes[type]) | 284 | if (itv->options.kilobytes[type]) |
284 | IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", | 285 | IVTV_INFO("Registered device %s for %s (%d kB)\n", |
285 | num, s->name, itv->options.kilobytes[type]); | 286 | name, s->name, itv->options.kilobytes[type]); |
286 | else | 287 | else |
287 | IVTV_INFO("Registered device vbi%d for %s\n", | 288 | IVTV_INFO("Registered device %s for %s\n", |
288 | num, s->name); | 289 | name, s->name); |
289 | break; | 290 | break; |
290 | } | 291 | } |
291 | return 0; | 292 | return 0; |
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 01e1eefcf1eb..6ffa64cd1c6d 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c | |||
@@ -1681,7 +1681,6 @@ static struct video_device meye_template = { | |||
1681 | .fops = &meye_fops, | 1681 | .fops = &meye_fops, |
1682 | .ioctl_ops = &meye_ioctl_ops, | 1682 | .ioctl_ops = &meye_ioctl_ops, |
1683 | .release = video_device_release, | 1683 | .release = video_device_release, |
1684 | .minor = -1, | ||
1685 | }; | 1684 | }; |
1686 | 1685 | ||
1687 | #ifdef CONFIG_PM | 1686 | #ifdef CONFIG_PM |
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 45388d2ce2fd..b62c0bd3f8ea 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -17,9 +17,11 @@ | |||
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9m001 i2c address 0x5d | 20 | /* |
21 | * mt9m001 i2c address 0x5d | ||
21 | * The platform has to define ctruct i2c_board_info objects and link to them | 22 | * The platform has to define ctruct i2c_board_info objects and link to them |
22 | * from struct soc_camera_link */ | 23 | * from struct soc_camera_link |
24 | */ | ||
23 | 25 | ||
24 | /* mt9m001 selected register addresses */ | 26 | /* mt9m001 selected register addresses */ |
25 | #define MT9M001_CHIP_VERSION 0x00 | 27 | #define MT9M001_CHIP_VERSION 0x00 |
@@ -46,42 +48,50 @@ | |||
46 | #define MT9M001_COLUMN_SKIP 20 | 48 | #define MT9M001_COLUMN_SKIP 20 |
47 | #define MT9M001_ROW_SKIP 12 | 49 | #define MT9M001_ROW_SKIP 12 |
48 | 50 | ||
49 | static const struct soc_camera_data_format mt9m001_colour_formats[] = { | 51 | /* MT9M001 has only one fixed colorspace per pixelcode */ |
50 | /* Order important: first natively supported, | 52 | struct mt9m001_datafmt { |
51 | * second supported with a GPIO extender */ | 53 | enum v4l2_mbus_pixelcode code; |
52 | { | 54 | enum v4l2_colorspace colorspace; |
53 | .name = "Bayer (sRGB) 10 bit", | 55 | }; |
54 | .depth = 10, | 56 | |
55 | .fourcc = V4L2_PIX_FMT_SBGGR16, | 57 | /* Find a data format by a pixel code in an array */ |
56 | .colorspace = V4L2_COLORSPACE_SRGB, | 58 | static const struct mt9m001_datafmt *mt9m001_find_datafmt( |
57 | }, { | 59 | enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt, |
58 | .name = "Bayer (sRGB) 8 bit", | 60 | int n) |
59 | .depth = 8, | 61 | { |
60 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 62 | int i; |
61 | .colorspace = V4L2_COLORSPACE_SRGB, | 63 | for (i = 0; i < n; i++) |
62 | } | 64 | if (fmt[i].code == code) |
65 | return fmt + i; | ||
66 | |||
67 | return NULL; | ||
68 | } | ||
69 | |||
70 | static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { | ||
71 | /* | ||
72 | * Order important: first natively supported, | ||
73 | * second supported with a GPIO extender | ||
74 | */ | ||
75 | {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, | ||
76 | {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, | ||
63 | }; | 77 | }; |
64 | 78 | ||
65 | static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { | 79 | static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { |
66 | /* Order important - see above */ | 80 | /* Order important - see above */ |
67 | { | 81 | {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, |
68 | .name = "Monochrome 10 bit", | 82 | {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, |
69 | .depth = 10, | ||
70 | .fourcc = V4L2_PIX_FMT_Y16, | ||
71 | }, { | ||
72 | .name = "Monochrome 8 bit", | ||
73 | .depth = 8, | ||
74 | .fourcc = V4L2_PIX_FMT_GREY, | ||
75 | }, | ||
76 | }; | 83 | }; |
77 | 84 | ||
78 | struct mt9m001 { | 85 | struct mt9m001 { |
79 | struct v4l2_subdev subdev; | 86 | struct v4l2_subdev subdev; |
80 | struct v4l2_rect rect; /* Sensor window */ | 87 | struct v4l2_rect rect; /* Sensor window */ |
81 | __u32 fourcc; | 88 | const struct mt9m001_datafmt *fmt; |
89 | const struct mt9m001_datafmt *fmts; | ||
90 | int num_fmts; | ||
82 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ | 91 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ |
83 | unsigned int gain; | 92 | unsigned int gain; |
84 | unsigned int exposure; | 93 | unsigned int exposure; |
94 | unsigned short y_skip_top; /* Lines to skip at the top */ | ||
85 | unsigned char autoexposure; | 95 | unsigned char autoexposure; |
86 | }; | 96 | }; |
87 | 97 | ||
@@ -204,8 +214,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
204 | const u16 hblank = 9, vblank = 25; | 214 | const u16 hblank = 9, vblank = 25; |
205 | unsigned int total_h; | 215 | unsigned int total_h; |
206 | 216 | ||
207 | if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 || | 217 | if (mt9m001->fmts == mt9m001_colour_fmts) |
208 | mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16) | ||
209 | /* | 218 | /* |
210 | * Bayer format - even number of rows for simplicity, | 219 | * Bayer format - even number of rows for simplicity, |
211 | * but let the user play with the top row. | 220 | * but let the user play with the top row. |
@@ -222,15 +231,17 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
222 | soc_camera_limit_side(&rect.top, &rect.height, | 231 | soc_camera_limit_side(&rect.top, &rect.height, |
223 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); | 232 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); |
224 | 233 | ||
225 | total_h = rect.height + icd->y_skip_top + vblank; | 234 | total_h = rect.height + mt9m001->y_skip_top + vblank; |
226 | 235 | ||
227 | /* Blanking and start values - default... */ | 236 | /* Blanking and start values - default... */ |
228 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); | 237 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); |
229 | if (!ret) | 238 | if (!ret) |
230 | ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); | 239 | ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); |
231 | 240 | ||
232 | /* The caller provides a supported format, as verified per | 241 | /* |
233 | * call to icd->try_fmt() */ | 242 | * The caller provides a supported format, as verified per |
243 | * call to icd->try_fmt() | ||
244 | */ | ||
234 | if (!ret) | 245 | if (!ret) |
235 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); | 246 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); |
236 | if (!ret) | 247 | if (!ret) |
@@ -239,7 +250,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
239 | ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); | 250 | ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); |
240 | if (!ret) | 251 | if (!ret) |
241 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, | 252 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, |
242 | rect.height + icd->y_skip_top - 1); | 253 | rect.height + mt9m001->y_skip_top - 1); |
243 | if (!ret && mt9m001->autoexposure) { | 254 | if (!ret && mt9m001->autoexposure) { |
244 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); | 255 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); |
245 | if (!ret) { | 256 | if (!ret) { |
@@ -283,32 +294,32 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
283 | return 0; | 294 | return 0; |
284 | } | 295 | } |
285 | 296 | ||
286 | static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 297 | static int mt9m001_g_fmt(struct v4l2_subdev *sd, |
298 | struct v4l2_mbus_framefmt *mf) | ||
287 | { | 299 | { |
288 | struct i2c_client *client = sd->priv; | 300 | struct i2c_client *client = sd->priv; |
289 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 301 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
290 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
291 | 302 | ||
292 | pix->width = mt9m001->rect.width; | 303 | mf->width = mt9m001->rect.width; |
293 | pix->height = mt9m001->rect.height; | 304 | mf->height = mt9m001->rect.height; |
294 | pix->pixelformat = mt9m001->fourcc; | 305 | mf->code = mt9m001->fmt->code; |
295 | pix->field = V4L2_FIELD_NONE; | 306 | mf->colorspace = mt9m001->fmt->colorspace; |
296 | pix->colorspace = V4L2_COLORSPACE_SRGB; | 307 | mf->field = V4L2_FIELD_NONE; |
297 | 308 | ||
298 | return 0; | 309 | return 0; |
299 | } | 310 | } |
300 | 311 | ||
301 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 312 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, |
313 | struct v4l2_mbus_framefmt *mf) | ||
302 | { | 314 | { |
303 | struct i2c_client *client = sd->priv; | 315 | struct i2c_client *client = sd->priv; |
304 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 316 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
305 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
306 | struct v4l2_crop a = { | 317 | struct v4l2_crop a = { |
307 | .c = { | 318 | .c = { |
308 | .left = mt9m001->rect.left, | 319 | .left = mt9m001->rect.left, |
309 | .top = mt9m001->rect.top, | 320 | .top = mt9m001->rect.top, |
310 | .width = pix->width, | 321 | .width = mf->width, |
311 | .height = pix->height, | 322 | .height = mf->height, |
312 | }, | 323 | }, |
313 | }; | 324 | }; |
314 | int ret; | 325 | int ret; |
@@ -316,28 +327,39 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
316 | /* No support for scaling so far, just crop. TODO: use skipping */ | 327 | /* No support for scaling so far, just crop. TODO: use skipping */ |
317 | ret = mt9m001_s_crop(sd, &a); | 328 | ret = mt9m001_s_crop(sd, &a); |
318 | if (!ret) { | 329 | if (!ret) { |
319 | pix->width = mt9m001->rect.width; | 330 | mf->width = mt9m001->rect.width; |
320 | pix->height = mt9m001->rect.height; | 331 | mf->height = mt9m001->rect.height; |
321 | mt9m001->fourcc = pix->pixelformat; | 332 | mt9m001->fmt = mt9m001_find_datafmt(mf->code, |
333 | mt9m001->fmts, mt9m001->num_fmts); | ||
334 | mf->colorspace = mt9m001->fmt->colorspace; | ||
322 | } | 335 | } |
323 | 336 | ||
324 | return ret; | 337 | return ret; |
325 | } | 338 | } |
326 | 339 | ||
327 | static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 340 | static int mt9m001_try_fmt(struct v4l2_subdev *sd, |
341 | struct v4l2_mbus_framefmt *mf) | ||
328 | { | 342 | { |
329 | struct i2c_client *client = sd->priv; | 343 | struct i2c_client *client = sd->priv; |
330 | struct soc_camera_device *icd = client->dev.platform_data; | 344 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
331 | struct v4l2_pix_format *pix = &f->fmt.pix; | 345 | const struct mt9m001_datafmt *fmt; |
332 | 346 | ||
333 | v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH, | 347 | v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, |
334 | MT9M001_MAX_WIDTH, 1, | 348 | MT9M001_MAX_WIDTH, 1, |
335 | &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top, | 349 | &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, |
336 | MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0); | 350 | MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0); |
351 | |||
352 | if (mt9m001->fmts == mt9m001_colour_fmts) | ||
353 | mf->height = ALIGN(mf->height - 1, 2); | ||
337 | 354 | ||
338 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | 355 | fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts, |
339 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16) | 356 | mt9m001->num_fmts); |
340 | pix->height = ALIGN(pix->height - 1, 2); | 357 | if (!fmt) { |
358 | fmt = mt9m001->fmt; | ||
359 | mf->code = fmt->code; | ||
360 | } | ||
361 | |||
362 | mf->colorspace = fmt->colorspace; | ||
341 | 363 | ||
342 | return 0; | 364 | return 0; |
343 | } | 365 | } |
@@ -552,7 +574,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
552 | if (ctrl->value) { | 574 | if (ctrl->value) { |
553 | const u16 vblank = 25; | 575 | const u16 vblank = 25; |
554 | unsigned int total_h = mt9m001->rect.height + | 576 | unsigned int total_h = mt9m001->rect.height + |
555 | icd->y_skip_top + vblank; | 577 | mt9m001->y_skip_top + vblank; |
556 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, | 578 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, |
557 | total_h) < 0) | 579 | total_h) < 0) |
558 | return -EIO; | 580 | return -EIO; |
@@ -568,8 +590,10 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
568 | return 0; | 590 | return 0; |
569 | } | 591 | } |
570 | 592 | ||
571 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 593 | /* |
572 | * this wasn't our capture interface, so, we wait for the right one */ | 594 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
595 | * this wasn't our capture interface, so, we wait for the right one | ||
596 | */ | ||
573 | static int mt9m001_video_probe(struct soc_camera_device *icd, | 597 | static int mt9m001_video_probe(struct soc_camera_device *icd, |
574 | struct i2c_client *client) | 598 | struct i2c_client *client) |
575 | { | 599 | { |
@@ -579,8 +603,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
579 | unsigned long flags; | 603 | unsigned long flags; |
580 | int ret; | 604 | int ret; |
581 | 605 | ||
582 | /* We must have a parent by now. And it cannot be a wrong one. | 606 | /* |
583 | * So this entire test is completely redundant. */ | 607 | * We must have a parent by now. And it cannot be a wrong one. |
608 | * So this entire test is completely redundant. | ||
609 | */ | ||
584 | if (!icd->dev.parent || | 610 | if (!icd->dev.parent || |
585 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 611 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
586 | return -ENODEV; | 612 | return -ENODEV; |
@@ -597,11 +623,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
597 | case 0x8411: | 623 | case 0x8411: |
598 | case 0x8421: | 624 | case 0x8421: |
599 | mt9m001->model = V4L2_IDENT_MT9M001C12ST; | 625 | mt9m001->model = V4L2_IDENT_MT9M001C12ST; |
600 | icd->formats = mt9m001_colour_formats; | 626 | mt9m001->fmts = mt9m001_colour_fmts; |
601 | break; | 627 | break; |
602 | case 0x8431: | 628 | case 0x8431: |
603 | mt9m001->model = V4L2_IDENT_MT9M001C12STM; | 629 | mt9m001->model = V4L2_IDENT_MT9M001C12STM; |
604 | icd->formats = mt9m001_monochrome_formats; | 630 | mt9m001->fmts = mt9m001_monochrome_fmts; |
605 | break; | 631 | break; |
606 | default: | 632 | default: |
607 | dev_err(&client->dev, | 633 | dev_err(&client->dev, |
@@ -609,7 +635,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
609 | return -ENODEV; | 635 | return -ENODEV; |
610 | } | 636 | } |
611 | 637 | ||
612 | icd->num_formats = 0; | 638 | mt9m001->num_fmts = 0; |
613 | 639 | ||
614 | /* | 640 | /* |
615 | * This is a 10bit sensor, so by default we only allow 10bit. | 641 | * This is a 10bit sensor, so by default we only allow 10bit. |
@@ -622,14 +648,14 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
622 | flags = SOCAM_DATAWIDTH_10; | 648 | flags = SOCAM_DATAWIDTH_10; |
623 | 649 | ||
624 | if (flags & SOCAM_DATAWIDTH_10) | 650 | if (flags & SOCAM_DATAWIDTH_10) |
625 | icd->num_formats++; | 651 | mt9m001->num_fmts++; |
626 | else | 652 | else |
627 | icd->formats++; | 653 | mt9m001->fmts++; |
628 | 654 | ||
629 | if (flags & SOCAM_DATAWIDTH_8) | 655 | if (flags & SOCAM_DATAWIDTH_8) |
630 | icd->num_formats++; | 656 | mt9m001->num_fmts++; |
631 | 657 | ||
632 | mt9m001->fourcc = icd->formats->fourcc; | 658 | mt9m001->fmt = &mt9m001->fmts[0]; |
633 | 659 | ||
634 | dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, | 660 | dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, |
635 | data == 0x8431 ? "C12STM" : "C12ST"); | 661 | data == 0x8431 ? "C12STM" : "C12ST"); |
@@ -655,6 +681,16 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) | |||
655 | icl->free_bus(icl); | 681 | icl->free_bus(icl); |
656 | } | 682 | } |
657 | 683 | ||
684 | static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | ||
685 | { | ||
686 | struct i2c_client *client = sd->priv; | ||
687 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
688 | |||
689 | *lines = mt9m001->y_skip_top; | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
658 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | 694 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { |
659 | .g_ctrl = mt9m001_g_ctrl, | 695 | .g_ctrl = mt9m001_g_ctrl, |
660 | .s_ctrl = mt9m001_s_ctrl, | 696 | .s_ctrl = mt9m001_s_ctrl, |
@@ -665,19 +701,38 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | |||
665 | #endif | 701 | #endif |
666 | }; | 702 | }; |
667 | 703 | ||
704 | static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index, | ||
705 | enum v4l2_mbus_pixelcode *code) | ||
706 | { | ||
707 | struct i2c_client *client = sd->priv; | ||
708 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
709 | |||
710 | if ((unsigned int)index >= mt9m001->num_fmts) | ||
711 | return -EINVAL; | ||
712 | |||
713 | *code = mt9m001->fmts[index].code; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
668 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | 717 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { |
669 | .s_stream = mt9m001_s_stream, | 718 | .s_stream = mt9m001_s_stream, |
670 | .s_fmt = mt9m001_s_fmt, | 719 | .s_mbus_fmt = mt9m001_s_fmt, |
671 | .g_fmt = mt9m001_g_fmt, | 720 | .g_mbus_fmt = mt9m001_g_fmt, |
672 | .try_fmt = mt9m001_try_fmt, | 721 | .try_mbus_fmt = mt9m001_try_fmt, |
673 | .s_crop = mt9m001_s_crop, | 722 | .s_crop = mt9m001_s_crop, |
674 | .g_crop = mt9m001_g_crop, | 723 | .g_crop = mt9m001_g_crop, |
675 | .cropcap = mt9m001_cropcap, | 724 | .cropcap = mt9m001_cropcap, |
725 | .enum_mbus_fmt = mt9m001_enum_fmt, | ||
726 | }; | ||
727 | |||
728 | static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { | ||
729 | .g_skip_top_lines = mt9m001_g_skip_top_lines, | ||
676 | }; | 730 | }; |
677 | 731 | ||
678 | static struct v4l2_subdev_ops mt9m001_subdev_ops = { | 732 | static struct v4l2_subdev_ops mt9m001_subdev_ops = { |
679 | .core = &mt9m001_subdev_core_ops, | 733 | .core = &mt9m001_subdev_core_ops, |
680 | .video = &mt9m001_subdev_video_ops, | 734 | .video = &mt9m001_subdev_video_ops, |
735 | .sensor = &mt9m001_subdev_sensor_ops, | ||
681 | }; | 736 | }; |
682 | 737 | ||
683 | static int mt9m001_probe(struct i2c_client *client, | 738 | static int mt9m001_probe(struct i2c_client *client, |
@@ -714,15 +769,17 @@ static int mt9m001_probe(struct i2c_client *client, | |||
714 | 769 | ||
715 | /* Second stage probe - when a capture adapter is there */ | 770 | /* Second stage probe - when a capture adapter is there */ |
716 | icd->ops = &mt9m001_ops; | 771 | icd->ops = &mt9m001_ops; |
717 | icd->y_skip_top = 0; | ||
718 | 772 | ||
773 | mt9m001->y_skip_top = 0; | ||
719 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; | 774 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; |
720 | mt9m001->rect.top = MT9M001_ROW_SKIP; | 775 | mt9m001->rect.top = MT9M001_ROW_SKIP; |
721 | mt9m001->rect.width = MT9M001_MAX_WIDTH; | 776 | mt9m001->rect.width = MT9M001_MAX_WIDTH; |
722 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; | 777 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; |
723 | 778 | ||
724 | /* Simulated autoexposure. If enabled, we calculate shutter width | 779 | /* |
725 | * ourselves in the driver based on vertical blanking and frame width */ | 780 | * Simulated autoexposure. If enabled, we calculate shutter width |
781 | * ourselves in the driver based on vertical blanking and frame width | ||
782 | */ | ||
726 | mt9m001->autoexposure = 1; | 783 | mt9m001->autoexposure = 1; |
727 | 784 | ||
728 | ret = mt9m001_video_probe(icd, client); | 785 | ret = mt9m001_video_probe(icd, client); |
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 90da699601ea..d35f536f9fc3 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -123,23 +123,34 @@ | |||
123 | #define MT9M111_MAX_HEIGHT 1024 | 123 | #define MT9M111_MAX_HEIGHT 1024 |
124 | #define MT9M111_MAX_WIDTH 1280 | 124 | #define MT9M111_MAX_WIDTH 1280 |
125 | 125 | ||
126 | #define COL_FMT(_name, _depth, _fourcc, _colorspace) \ | 126 | /* MT9M111 has only one fixed colorspace per pixelcode */ |
127 | { .name = _name, .depth = _depth, .fourcc = _fourcc, \ | 127 | struct mt9m111_datafmt { |
128 | .colorspace = _colorspace } | 128 | enum v4l2_mbus_pixelcode code; |
129 | #define RGB_FMT(_name, _depth, _fourcc) \ | 129 | enum v4l2_colorspace colorspace; |
130 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) | 130 | }; |
131 | #define JPG_FMT(_name, _depth, _fourcc) \ | 131 | |
132 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) | 132 | /* Find a data format by a pixel code in an array */ |
133 | 133 | static const struct mt9m111_datafmt *mt9m111_find_datafmt( | |
134 | static const struct soc_camera_data_format mt9m111_colour_formats[] = { | 134 | enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, |
135 | JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY), | 135 | int n) |
136 | JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY), | 136 | { |
137 | JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV), | 137 | int i; |
138 | JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU), | 138 | for (i = 0; i < n; i++) |
139 | RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), | 139 | if (fmt[i].code == code) |
140 | RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), | 140 | return fmt + i; |
141 | RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), | 141 | |
142 | RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8), | 142 | return NULL; |
143 | } | ||
144 | |||
145 | static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { | ||
146 | {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
147 | {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
148 | {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG}, | ||
149 | {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG}, | ||
150 | {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, | ||
151 | {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, | ||
152 | {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, | ||
153 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, | ||
143 | }; | 154 | }; |
144 | 155 | ||
145 | enum mt9m111_context { | 156 | enum mt9m111_context { |
@@ -152,7 +163,7 @@ struct mt9m111 { | |||
152 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ | 163 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ |
153 | enum mt9m111_context context; | 164 | enum mt9m111_context context; |
154 | struct v4l2_rect rect; | 165 | struct v4l2_rect rect; |
155 | u32 pixfmt; | 166 | const struct mt9m111_datafmt *fmt; |
156 | unsigned int gain; | 167 | unsigned int gain; |
157 | unsigned char autoexposure; | 168 | unsigned char autoexposure; |
158 | unsigned char datawidth; | 169 | unsigned char datawidth; |
@@ -258,8 +269,8 @@ static int mt9m111_setup_rect(struct i2c_client *client, | |||
258 | int width = rect->width; | 269 | int width = rect->width; |
259 | int height = rect->height; | 270 | int height = rect->height; |
260 | 271 | ||
261 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || | 272 | if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || |
262 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) | 273 | mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) |
263 | is_raw_format = 1; | 274 | is_raw_format = 1; |
264 | else | 275 | else |
265 | is_raw_format = 0; | 276 | is_raw_format = 0; |
@@ -307,7 +318,8 @@ static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) | |||
307 | 318 | ||
308 | static int mt9m111_setfmt_bayer8(struct i2c_client *client) | 319 | static int mt9m111_setfmt_bayer8(struct i2c_client *client) |
309 | { | 320 | { |
310 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER); | 321 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER | |
322 | MT9M111_OUTFMT_RGB); | ||
311 | } | 323 | } |
312 | 324 | ||
313 | static int mt9m111_setfmt_bayer10(struct i2c_client *client) | 325 | static int mt9m111_setfmt_bayer10(struct i2c_client *client) |
@@ -401,8 +413,8 @@ static int mt9m111_make_rect(struct i2c_client *client, | |||
401 | { | 413 | { |
402 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 414 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
403 | 415 | ||
404 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || | 416 | if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || |
405 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) { | 417 | mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { |
406 | /* Bayer format - even size lengths */ | 418 | /* Bayer format - even size lengths */ |
407 | rect->width = ALIGN(rect->width, 2); | 419 | rect->width = ALIGN(rect->width, 2); |
408 | rect->height = ALIGN(rect->height, 2); | 420 | rect->height = ALIGN(rect->height, 2); |
@@ -460,120 +472,139 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
460 | return 0; | 472 | return 0; |
461 | } | 473 | } |
462 | 474 | ||
463 | static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 475 | static int mt9m111_g_fmt(struct v4l2_subdev *sd, |
476 | struct v4l2_mbus_framefmt *mf) | ||
464 | { | 477 | { |
465 | struct i2c_client *client = sd->priv; | 478 | struct i2c_client *client = sd->priv; |
466 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 479 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
467 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
468 | 480 | ||
469 | pix->width = mt9m111->rect.width; | 481 | mf->width = mt9m111->rect.width; |
470 | pix->height = mt9m111->rect.height; | 482 | mf->height = mt9m111->rect.height; |
471 | pix->pixelformat = mt9m111->pixfmt; | 483 | mf->code = mt9m111->fmt->code; |
472 | pix->field = V4L2_FIELD_NONE; | 484 | mf->field = V4L2_FIELD_NONE; |
473 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
474 | 485 | ||
475 | return 0; | 486 | return 0; |
476 | } | 487 | } |
477 | 488 | ||
478 | static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) | 489 | static int mt9m111_set_pixfmt(struct i2c_client *client, |
490 | enum v4l2_mbus_pixelcode code) | ||
479 | { | 491 | { |
480 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 492 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
481 | int ret; | 493 | int ret; |
482 | 494 | ||
483 | switch (pixfmt) { | 495 | switch (code) { |
484 | case V4L2_PIX_FMT_SBGGR8: | 496 | case V4L2_MBUS_FMT_SBGGR8_1X8: |
485 | ret = mt9m111_setfmt_bayer8(client); | 497 | ret = mt9m111_setfmt_bayer8(client); |
486 | break; | 498 | break; |
487 | case V4L2_PIX_FMT_SBGGR16: | 499 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: |
488 | ret = mt9m111_setfmt_bayer10(client); | 500 | ret = mt9m111_setfmt_bayer10(client); |
489 | break; | 501 | break; |
490 | case V4L2_PIX_FMT_RGB555: | 502 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: |
491 | ret = mt9m111_setfmt_rgb555(client); | 503 | ret = mt9m111_setfmt_rgb555(client); |
492 | break; | 504 | break; |
493 | case V4L2_PIX_FMT_RGB565: | 505 | case V4L2_MBUS_FMT_RGB565_2X8_LE: |
494 | ret = mt9m111_setfmt_rgb565(client); | 506 | ret = mt9m111_setfmt_rgb565(client); |
495 | break; | 507 | break; |
496 | case V4L2_PIX_FMT_UYVY: | 508 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
497 | mt9m111->swap_yuv_y_chromas = 0; | 509 | mt9m111->swap_yuv_y_chromas = 0; |
498 | mt9m111->swap_yuv_cb_cr = 0; | 510 | mt9m111->swap_yuv_cb_cr = 0; |
499 | ret = mt9m111_setfmt_yuv(client); | 511 | ret = mt9m111_setfmt_yuv(client); |
500 | break; | 512 | break; |
501 | case V4L2_PIX_FMT_VYUY: | 513 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
502 | mt9m111->swap_yuv_y_chromas = 0; | 514 | mt9m111->swap_yuv_y_chromas = 0; |
503 | mt9m111->swap_yuv_cb_cr = 1; | 515 | mt9m111->swap_yuv_cb_cr = 1; |
504 | ret = mt9m111_setfmt_yuv(client); | 516 | ret = mt9m111_setfmt_yuv(client); |
505 | break; | 517 | break; |
506 | case V4L2_PIX_FMT_YUYV: | 518 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
507 | mt9m111->swap_yuv_y_chromas = 1; | 519 | mt9m111->swap_yuv_y_chromas = 1; |
508 | mt9m111->swap_yuv_cb_cr = 0; | 520 | mt9m111->swap_yuv_cb_cr = 0; |
509 | ret = mt9m111_setfmt_yuv(client); | 521 | ret = mt9m111_setfmt_yuv(client); |
510 | break; | 522 | break; |
511 | case V4L2_PIX_FMT_YVYU: | 523 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
512 | mt9m111->swap_yuv_y_chromas = 1; | 524 | mt9m111->swap_yuv_y_chromas = 1; |
513 | mt9m111->swap_yuv_cb_cr = 1; | 525 | mt9m111->swap_yuv_cb_cr = 1; |
514 | ret = mt9m111_setfmt_yuv(client); | 526 | ret = mt9m111_setfmt_yuv(client); |
515 | break; | 527 | break; |
516 | default: | 528 | default: |
517 | dev_err(&client->dev, "Pixel format not handled : %x\n", | 529 | dev_err(&client->dev, "Pixel format not handled : %x\n", |
518 | pixfmt); | 530 | code); |
519 | ret = -EINVAL; | 531 | ret = -EINVAL; |
520 | } | 532 | } |
521 | 533 | ||
522 | if (!ret) | ||
523 | mt9m111->pixfmt = pixfmt; | ||
524 | |||
525 | return ret; | 534 | return ret; |
526 | } | 535 | } |
527 | 536 | ||
528 | static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 537 | static int mt9m111_s_fmt(struct v4l2_subdev *sd, |
538 | struct v4l2_mbus_framefmt *mf) | ||
529 | { | 539 | { |
530 | struct i2c_client *client = sd->priv; | 540 | struct i2c_client *client = sd->priv; |
541 | const struct mt9m111_datafmt *fmt; | ||
531 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 542 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
532 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
533 | struct v4l2_rect rect = { | 543 | struct v4l2_rect rect = { |
534 | .left = mt9m111->rect.left, | 544 | .left = mt9m111->rect.left, |
535 | .top = mt9m111->rect.top, | 545 | .top = mt9m111->rect.top, |
536 | .width = pix->width, | 546 | .width = mf->width, |
537 | .height = pix->height, | 547 | .height = mf->height, |
538 | }; | 548 | }; |
539 | int ret; | 549 | int ret; |
540 | 550 | ||
551 | fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, | ||
552 | ARRAY_SIZE(mt9m111_colour_fmts)); | ||
553 | if (!fmt) | ||
554 | return -EINVAL; | ||
555 | |||
541 | dev_dbg(&client->dev, | 556 | dev_dbg(&client->dev, |
542 | "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__, | 557 | "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, |
543 | pix->pixelformat, rect.left, rect.top, rect.width, rect.height); | 558 | mf->code, rect.left, rect.top, rect.width, rect.height); |
544 | 559 | ||
545 | ret = mt9m111_make_rect(client, &rect); | 560 | ret = mt9m111_make_rect(client, &rect); |
546 | if (!ret) | 561 | if (!ret) |
547 | ret = mt9m111_set_pixfmt(client, pix->pixelformat); | 562 | ret = mt9m111_set_pixfmt(client, mf->code); |
548 | if (!ret) | 563 | if (!ret) { |
549 | mt9m111->rect = rect; | 564 | mt9m111->rect = rect; |
565 | mt9m111->fmt = fmt; | ||
566 | mf->colorspace = fmt->colorspace; | ||
567 | } | ||
568 | |||
550 | return ret; | 569 | return ret; |
551 | } | 570 | } |
552 | 571 | ||
553 | static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 572 | static int mt9m111_try_fmt(struct v4l2_subdev *sd, |
573 | struct v4l2_mbus_framefmt *mf) | ||
554 | { | 574 | { |
555 | struct v4l2_pix_format *pix = &f->fmt.pix; | 575 | struct i2c_client *client = sd->priv; |
556 | bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | 576 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
557 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | 577 | const struct mt9m111_datafmt *fmt; |
578 | bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || | ||
579 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; | ||
580 | |||
581 | fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, | ||
582 | ARRAY_SIZE(mt9m111_colour_fmts)); | ||
583 | if (!fmt) { | ||
584 | fmt = mt9m111->fmt; | ||
585 | mf->code = fmt->code; | ||
586 | } | ||
558 | 587 | ||
559 | /* | 588 | /* |
560 | * With Bayer format enforce even side lengths, but let the user play | 589 | * With Bayer format enforce even side lengths, but let the user play |
561 | * with the starting pixel | 590 | * with the starting pixel |
562 | */ | 591 | */ |
563 | 592 | ||
564 | if (pix->height > MT9M111_MAX_HEIGHT) | 593 | if (mf->height > MT9M111_MAX_HEIGHT) |
565 | pix->height = MT9M111_MAX_HEIGHT; | 594 | mf->height = MT9M111_MAX_HEIGHT; |
566 | else if (pix->height < 2) | 595 | else if (mf->height < 2) |
567 | pix->height = 2; | 596 | mf->height = 2; |
568 | else if (bayer) | 597 | else if (bayer) |
569 | pix->height = ALIGN(pix->height, 2); | 598 | mf->height = ALIGN(mf->height, 2); |
570 | 599 | ||
571 | if (pix->width > MT9M111_MAX_WIDTH) | 600 | if (mf->width > MT9M111_MAX_WIDTH) |
572 | pix->width = MT9M111_MAX_WIDTH; | 601 | mf->width = MT9M111_MAX_WIDTH; |
573 | else if (pix->width < 2) | 602 | else if (mf->width < 2) |
574 | pix->width = 2; | 603 | mf->width = 2; |
575 | else if (bayer) | 604 | else if (bayer) |
576 | pix->width = ALIGN(pix->width, 2); | 605 | mf->width = ALIGN(mf->width, 2); |
606 | |||
607 | mf->colorspace = fmt->colorspace; | ||
577 | 608 | ||
578 | return 0; | 609 | return 0; |
579 | } | 610 | } |
@@ -863,7 +894,7 @@ static int mt9m111_restore_state(struct i2c_client *client) | |||
863 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 894 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
864 | 895 | ||
865 | mt9m111_set_context(client, mt9m111->context); | 896 | mt9m111_set_context(client, mt9m111->context); |
866 | mt9m111_set_pixfmt(client, mt9m111->pixfmt); | 897 | mt9m111_set_pixfmt(client, mt9m111->fmt->code); |
867 | mt9m111_setup_rect(client, &mt9m111->rect); | 898 | mt9m111_setup_rect(client, &mt9m111->rect); |
868 | mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 899 | mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); |
869 | mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | 900 | mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); |
@@ -952,9 +983,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, | |||
952 | goto ei2c; | 983 | goto ei2c; |
953 | } | 984 | } |
954 | 985 | ||
955 | icd->formats = mt9m111_colour_formats; | ||
956 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | ||
957 | |||
958 | dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data); | 986 | dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data); |
959 | 987 | ||
960 | ei2c: | 988 | ei2c: |
@@ -971,13 +999,24 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { | |||
971 | #endif | 999 | #endif |
972 | }; | 1000 | }; |
973 | 1001 | ||
1002 | static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index, | ||
1003 | enum v4l2_mbus_pixelcode *code) | ||
1004 | { | ||
1005 | if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts)) | ||
1006 | return -EINVAL; | ||
1007 | |||
1008 | *code = mt9m111_colour_fmts[index].code; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
974 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 1012 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
975 | .s_fmt = mt9m111_s_fmt, | 1013 | .s_mbus_fmt = mt9m111_s_fmt, |
976 | .g_fmt = mt9m111_g_fmt, | 1014 | .g_mbus_fmt = mt9m111_g_fmt, |
977 | .try_fmt = mt9m111_try_fmt, | 1015 | .try_mbus_fmt = mt9m111_try_fmt, |
978 | .s_crop = mt9m111_s_crop, | 1016 | .s_crop = mt9m111_s_crop, |
979 | .g_crop = mt9m111_g_crop, | 1017 | .g_crop = mt9m111_g_crop, |
980 | .cropcap = mt9m111_cropcap, | 1018 | .cropcap = mt9m111_cropcap, |
1019 | .enum_mbus_fmt = mt9m111_enum_fmt, | ||
981 | }; | 1020 | }; |
982 | 1021 | ||
983 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | 1022 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { |
@@ -1019,12 +1058,12 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1019 | 1058 | ||
1020 | /* Second stage probe - when a capture adapter is there */ | 1059 | /* Second stage probe - when a capture adapter is there */ |
1021 | icd->ops = &mt9m111_ops; | 1060 | icd->ops = &mt9m111_ops; |
1022 | icd->y_skip_top = 0; | ||
1023 | 1061 | ||
1024 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; | 1062 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
1025 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; | 1063 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
1026 | mt9m111->rect.width = MT9M111_MAX_WIDTH; | 1064 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
1027 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; | 1065 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
1066 | mt9m111->fmt = &mt9m111_colour_fmts[0]; | ||
1028 | 1067 | ||
1029 | ret = mt9m111_video_probe(icd, client); | 1068 | ret = mt9m111_video_probe(icd, client); |
1030 | if (ret) { | 1069 | if (ret) { |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 6966f644977e..a9061bff79b2 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -17,9 +17,11 @@ | |||
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9t031 i2c address 0x5d | 20 | /* |
21 | * mt9t031 i2c address 0x5d | ||
21 | * The platform has to define i2c_board_info and link to it from | 22 | * The platform has to define i2c_board_info and link to it from |
22 | * struct soc_camera_link */ | 23 | * struct soc_camera_link |
24 | */ | ||
23 | 25 | ||
24 | /* mt9t031 selected register addresses */ | 26 | /* mt9t031 selected register addresses */ |
25 | #define MT9T031_CHIP_VERSION 0x00 | 27 | #define MT9T031_CHIP_VERSION 0x00 |
@@ -58,15 +60,6 @@ | |||
58 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ | 60 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ |
59 | SOCAM_MASTER | SOCAM_DATAWIDTH_10) | 61 | SOCAM_MASTER | SOCAM_DATAWIDTH_10) |
60 | 62 | ||
61 | static const struct soc_camera_data_format mt9t031_colour_formats[] = { | ||
62 | { | ||
63 | .name = "Bayer (sRGB) 10 bit", | ||
64 | .depth = 10, | ||
65 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
66 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
67 | } | ||
68 | }; | ||
69 | |||
70 | struct mt9t031 { | 63 | struct mt9t031 { |
71 | struct v4l2_subdev subdev; | 64 | struct v4l2_subdev subdev; |
72 | struct v4l2_rect rect; /* Sensor window */ | 65 | struct v4l2_rect rect; /* Sensor window */ |
@@ -74,6 +67,7 @@ struct mt9t031 { | |||
74 | u16 xskip; | 67 | u16 xskip; |
75 | u16 yskip; | 68 | u16 yskip; |
76 | unsigned int gain; | 69 | unsigned int gain; |
70 | unsigned short y_skip_top; /* Lines to skip at the top */ | ||
77 | unsigned int exposure; | 71 | unsigned int exposure; |
78 | unsigned char autoexposure; | 72 | unsigned char autoexposure; |
79 | }; | 73 | }; |
@@ -207,6 +201,71 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) | |||
207 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); | 201 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); |
208 | } | 202 | } |
209 | 203 | ||
204 | enum { | ||
205 | MT9T031_CTRL_VFLIP, | ||
206 | MT9T031_CTRL_HFLIP, | ||
207 | MT9T031_CTRL_GAIN, | ||
208 | MT9T031_CTRL_EXPOSURE, | ||
209 | MT9T031_CTRL_EXPOSURE_AUTO, | ||
210 | }; | ||
211 | |||
212 | static const struct v4l2_queryctrl mt9t031_controls[] = { | ||
213 | [MT9T031_CTRL_VFLIP] = { | ||
214 | .id = V4L2_CID_VFLIP, | ||
215 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
216 | .name = "Flip Vertically", | ||
217 | .minimum = 0, | ||
218 | .maximum = 1, | ||
219 | .step = 1, | ||
220 | .default_value = 0, | ||
221 | }, | ||
222 | [MT9T031_CTRL_HFLIP] = { | ||
223 | .id = V4L2_CID_HFLIP, | ||
224 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
225 | .name = "Flip Horizontally", | ||
226 | .minimum = 0, | ||
227 | .maximum = 1, | ||
228 | .step = 1, | ||
229 | .default_value = 0, | ||
230 | }, | ||
231 | [MT9T031_CTRL_GAIN] = { | ||
232 | .id = V4L2_CID_GAIN, | ||
233 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
234 | .name = "Gain", | ||
235 | .minimum = 0, | ||
236 | .maximum = 127, | ||
237 | .step = 1, | ||
238 | .default_value = 64, | ||
239 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
240 | }, | ||
241 | [MT9T031_CTRL_EXPOSURE] = { | ||
242 | .id = V4L2_CID_EXPOSURE, | ||
243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
244 | .name = "Exposure", | ||
245 | .minimum = 1, | ||
246 | .maximum = 255, | ||
247 | .step = 1, | ||
248 | .default_value = 255, | ||
249 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
250 | }, | ||
251 | [MT9T031_CTRL_EXPOSURE_AUTO] = { | ||
252 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
253 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
254 | .name = "Automatic Exposure", | ||
255 | .minimum = 0, | ||
256 | .maximum = 1, | ||
257 | .step = 1, | ||
258 | .default_value = 1, | ||
259 | } | ||
260 | }; | ||
261 | |||
262 | static struct soc_camera_ops mt9t031_ops = { | ||
263 | .set_bus_param = mt9t031_set_bus_param, | ||
264 | .query_bus_param = mt9t031_query_bus_param, | ||
265 | .controls = mt9t031_controls, | ||
266 | .num_controls = ARRAY_SIZE(mt9t031_controls), | ||
267 | }; | ||
268 | |||
210 | /* target must be _even_ */ | 269 | /* target must be _even_ */ |
211 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) | 270 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
212 | { | 271 | { |
@@ -226,10 +285,9 @@ static u16 mt9t031_skip(s32 *source, s32 target, s32 max) | |||
226 | } | 285 | } |
227 | 286 | ||
228 | /* rect is the sensor rectangle, the caller guarantees parameter validity */ | 287 | /* rect is the sensor rectangle, the caller guarantees parameter validity */ |
229 | static int mt9t031_set_params(struct soc_camera_device *icd, | 288 | static int mt9t031_set_params(struct i2c_client *client, |
230 | struct v4l2_rect *rect, u16 xskip, u16 yskip) | 289 | struct v4l2_rect *rect, u16 xskip, u16 yskip) |
231 | { | 290 | { |
232 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
233 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 291 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
234 | int ret; | 292 | int ret; |
235 | u16 xbin, ybin; | 293 | u16 xbin, ybin; |
@@ -291,8 +349,10 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
291 | dev_dbg(&client->dev, "new physical left %u, top %u\n", | 349 | dev_dbg(&client->dev, "new physical left %u, top %u\n", |
292 | rect->left, rect->top); | 350 | rect->left, rect->top); |
293 | 351 | ||
294 | /* The caller provides a supported format, as guaranteed by | 352 | /* |
295 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ | 353 | * The caller provides a supported format, as guaranteed by |
354 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() | ||
355 | */ | ||
296 | if (ret >= 0) | 356 | if (ret >= 0) |
297 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); | 357 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
298 | if (ret >= 0) | 358 | if (ret >= 0) |
@@ -301,15 +361,14 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
301 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); | 361 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); |
302 | if (ret >= 0) | 362 | if (ret >= 0) |
303 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 363 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
304 | rect->height + icd->y_skip_top - 1); | 364 | rect->height + mt9t031->y_skip_top - 1); |
305 | if (ret >= 0 && mt9t031->autoexposure) { | 365 | if (ret >= 0 && mt9t031->autoexposure) { |
306 | unsigned int total_h = rect->height + icd->y_skip_top + vblank; | 366 | unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; |
307 | ret = set_shutter(client, total_h); | 367 | ret = set_shutter(client, total_h); |
308 | if (ret >= 0) { | 368 | if (ret >= 0) { |
309 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 369 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
310 | const struct v4l2_queryctrl *qctrl = | 370 | const struct v4l2_queryctrl *qctrl = |
311 | soc_camera_find_qctrl(icd->ops, | 371 | &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; |
312 | V4L2_CID_EXPOSURE); | ||
313 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | 372 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
314 | (qctrl->maximum - qctrl->minimum)) / | 373 | (qctrl->maximum - qctrl->minimum)) / |
315 | shutter_max + qctrl->minimum; | 374 | shutter_max + qctrl->minimum; |
@@ -334,7 +393,6 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
334 | struct v4l2_rect rect = a->c; | 393 | struct v4l2_rect rect = a->c; |
335 | struct i2c_client *client = sd->priv; | 394 | struct i2c_client *client = sd->priv; |
336 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 395 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
337 | struct soc_camera_device *icd = client->dev.platform_data; | ||
338 | 396 | ||
339 | rect.width = ALIGN(rect.width, 2); | 397 | rect.width = ALIGN(rect.width, 2); |
340 | rect.height = ALIGN(rect.height, 2); | 398 | rect.height = ALIGN(rect.height, 2); |
@@ -345,7 +403,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
345 | soc_camera_limit_side(&rect.top, &rect.height, | 403 | soc_camera_limit_side(&rect.top, &rect.height, |
346 | MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); | 404 | MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); |
347 | 405 | ||
348 | return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip); | 406 | return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); |
349 | } | 407 | } |
350 | 408 | ||
351 | static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 409 | static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
@@ -373,27 +431,26 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
373 | return 0; | 431 | return 0; |
374 | } | 432 | } |
375 | 433 | ||
376 | static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 434 | static int mt9t031_g_fmt(struct v4l2_subdev *sd, |
435 | struct v4l2_mbus_framefmt *mf) | ||
377 | { | 436 | { |
378 | struct i2c_client *client = sd->priv; | 437 | struct i2c_client *client = sd->priv; |
379 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 438 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
380 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
381 | 439 | ||
382 | pix->width = mt9t031->rect.width / mt9t031->xskip; | 440 | mf->width = mt9t031->rect.width / mt9t031->xskip; |
383 | pix->height = mt9t031->rect.height / mt9t031->yskip; | 441 | mf->height = mt9t031->rect.height / mt9t031->yskip; |
384 | pix->pixelformat = V4L2_PIX_FMT_SGRBG10; | 442 | mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; |
385 | pix->field = V4L2_FIELD_NONE; | 443 | mf->colorspace = V4L2_COLORSPACE_SRGB; |
386 | pix->colorspace = V4L2_COLORSPACE_SRGB; | 444 | mf->field = V4L2_FIELD_NONE; |
387 | 445 | ||
388 | return 0; | 446 | return 0; |
389 | } | 447 | } |
390 | 448 | ||
391 | static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 449 | static int mt9t031_s_fmt(struct v4l2_subdev *sd, |
450 | struct v4l2_mbus_framefmt *mf) | ||
392 | { | 451 | { |
393 | struct i2c_client *client = sd->priv; | 452 | struct i2c_client *client = sd->priv; |
394 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 453 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
395 | struct soc_camera_device *icd = client->dev.platform_data; | ||
396 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
397 | u16 xskip, yskip; | 454 | u16 xskip, yskip; |
398 | struct v4l2_rect rect = mt9t031->rect; | 455 | struct v4l2_rect rect = mt9t031->rect; |
399 | 456 | ||
@@ -401,24 +458,29 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
401 | * try_fmt has put width and height within limits. | 458 | * try_fmt has put width and height within limits. |
402 | * S_FMT: use binning and skipping for scaling | 459 | * S_FMT: use binning and skipping for scaling |
403 | */ | 460 | */ |
404 | xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH); | 461 | xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); |
405 | yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT); | 462 | yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT); |
463 | |||
464 | mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; | ||
465 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
406 | 466 | ||
407 | /* mt9t031_set_params() doesn't change width and height */ | 467 | /* mt9t031_set_params() doesn't change width and height */ |
408 | return mt9t031_set_params(icd, &rect, xskip, yskip); | 468 | return mt9t031_set_params(client, &rect, xskip, yskip); |
409 | } | 469 | } |
410 | 470 | ||
411 | /* | 471 | /* |
412 | * If a user window larger than sensor window is requested, we'll increase the | 472 | * If a user window larger than sensor window is requested, we'll increase the |
413 | * sensor window. | 473 | * sensor window. |
414 | */ | 474 | */ |
415 | static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 475 | static int mt9t031_try_fmt(struct v4l2_subdev *sd, |
476 | struct v4l2_mbus_framefmt *mf) | ||
416 | { | 477 | { |
417 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
418 | |||
419 | v4l_bound_align_image( | 478 | v4l_bound_align_image( |
420 | &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, | 479 | &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, |
421 | &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); | 480 | &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); |
481 | |||
482 | mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; | ||
483 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
422 | 484 | ||
423 | return 0; | 485 | return 0; |
424 | } | 486 | } |
@@ -479,59 +541,6 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, | |||
479 | } | 541 | } |
480 | #endif | 542 | #endif |
481 | 543 | ||
482 | static const struct v4l2_queryctrl mt9t031_controls[] = { | ||
483 | { | ||
484 | .id = V4L2_CID_VFLIP, | ||
485 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
486 | .name = "Flip Vertically", | ||
487 | .minimum = 0, | ||
488 | .maximum = 1, | ||
489 | .step = 1, | ||
490 | .default_value = 0, | ||
491 | }, { | ||
492 | .id = V4L2_CID_HFLIP, | ||
493 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
494 | .name = "Flip Horizontally", | ||
495 | .minimum = 0, | ||
496 | .maximum = 1, | ||
497 | .step = 1, | ||
498 | .default_value = 0, | ||
499 | }, { | ||
500 | .id = V4L2_CID_GAIN, | ||
501 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
502 | .name = "Gain", | ||
503 | .minimum = 0, | ||
504 | .maximum = 127, | ||
505 | .step = 1, | ||
506 | .default_value = 64, | ||
507 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
508 | }, { | ||
509 | .id = V4L2_CID_EXPOSURE, | ||
510 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
511 | .name = "Exposure", | ||
512 | .minimum = 1, | ||
513 | .maximum = 255, | ||
514 | .step = 1, | ||
515 | .default_value = 255, | ||
516 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
517 | }, { | ||
518 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
519 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
520 | .name = "Automatic Exposure", | ||
521 | .minimum = 0, | ||
522 | .maximum = 1, | ||
523 | .step = 1, | ||
524 | .default_value = 1, | ||
525 | } | ||
526 | }; | ||
527 | |||
528 | static struct soc_camera_ops mt9t031_ops = { | ||
529 | .set_bus_param = mt9t031_set_bus_param, | ||
530 | .query_bus_param = mt9t031_query_bus_param, | ||
531 | .controls = mt9t031_controls, | ||
532 | .num_controls = ARRAY_SIZE(mt9t031_controls), | ||
533 | }; | ||
534 | |||
535 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 544 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
536 | { | 545 | { |
537 | struct i2c_client *client = sd->priv; | 546 | struct i2c_client *client = sd->priv; |
@@ -568,15 +577,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
568 | { | 577 | { |
569 | struct i2c_client *client = sd->priv; | 578 | struct i2c_client *client = sd->priv; |
570 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 579 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
571 | struct soc_camera_device *icd = client->dev.platform_data; | ||
572 | const struct v4l2_queryctrl *qctrl; | 580 | const struct v4l2_queryctrl *qctrl; |
573 | int data; | 581 | int data; |
574 | 582 | ||
575 | qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id); | ||
576 | |||
577 | if (!qctrl) | ||
578 | return -EINVAL; | ||
579 | |||
580 | switch (ctrl->id) { | 583 | switch (ctrl->id) { |
581 | case V4L2_CID_VFLIP: | 584 | case V4L2_CID_VFLIP: |
582 | if (ctrl->value) | 585 | if (ctrl->value) |
@@ -595,6 +598,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
595 | return -EIO; | 598 | return -EIO; |
596 | break; | 599 | break; |
597 | case V4L2_CID_GAIN: | 600 | case V4L2_CID_GAIN: |
601 | qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; | ||
598 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 602 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) |
599 | return -EINVAL; | 603 | return -EINVAL; |
600 | /* See Datasheet Table 7, Gain settings. */ | 604 | /* See Datasheet Table 7, Gain settings. */ |
@@ -634,6 +638,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
634 | mt9t031->gain = ctrl->value; | 638 | mt9t031->gain = ctrl->value; |
635 | break; | 639 | break; |
636 | case V4L2_CID_EXPOSURE: | 640 | case V4L2_CID_EXPOSURE: |
641 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | ||
637 | /* mt9t031 has maximum == default */ | 642 | /* mt9t031 has maximum == default */ |
638 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 643 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) |
639 | return -EINVAL; | 644 | return -EINVAL; |
@@ -657,11 +662,11 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
657 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 662 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
658 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 663 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
659 | unsigned int total_h = mt9t031->rect.height + | 664 | unsigned int total_h = mt9t031->rect.height + |
660 | icd->y_skip_top + vblank; | 665 | mt9t031->y_skip_top + vblank; |
661 | 666 | ||
662 | if (set_shutter(client, total_h) < 0) | 667 | if (set_shutter(client, total_h) < 0) |
663 | return -EIO; | 668 | return -EIO; |
664 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 669 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; |
665 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | 670 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
666 | (qctrl->maximum - qctrl->minimum)) / | 671 | (qctrl->maximum - qctrl->minimum)) / |
667 | shutter_max + qctrl->minimum; | 672 | shutter_max + qctrl->minimum; |
@@ -669,15 +674,18 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
669 | } else | 674 | } else |
670 | mt9t031->autoexposure = 0; | 675 | mt9t031->autoexposure = 0; |
671 | break; | 676 | break; |
677 | default: | ||
678 | return -EINVAL; | ||
672 | } | 679 | } |
673 | return 0; | 680 | return 0; |
674 | } | 681 | } |
675 | 682 | ||
676 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 683 | /* |
677 | * this wasn't our capture interface, so, we wait for the right one */ | 684 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
685 | * this wasn't our capture interface, so, we wait for the right one | ||
686 | */ | ||
678 | static int mt9t031_video_probe(struct i2c_client *client) | 687 | static int mt9t031_video_probe(struct i2c_client *client) |
679 | { | 688 | { |
680 | struct soc_camera_device *icd = client->dev.platform_data; | ||
681 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 689 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
682 | s32 data; | 690 | s32 data; |
683 | int ret; | 691 | int ret; |
@@ -692,8 +700,6 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
692 | switch (data) { | 700 | switch (data) { |
693 | case 0x1621: | 701 | case 0x1621: |
694 | mt9t031->model = V4L2_IDENT_MT9T031; | 702 | mt9t031->model = V4L2_IDENT_MT9T031; |
695 | icd->formats = mt9t031_colour_formats; | ||
696 | icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); | ||
697 | break; | 703 | break; |
698 | default: | 704 | default: |
699 | dev_err(&client->dev, | 705 | dev_err(&client->dev, |
@@ -714,6 +720,16 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
714 | return ret; | 720 | return ret; |
715 | } | 721 | } |
716 | 722 | ||
723 | static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | ||
724 | { | ||
725 | struct i2c_client *client = sd->priv; | ||
726 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
727 | |||
728 | *lines = mt9t031->y_skip_top; | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | |||
717 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | 733 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
718 | .g_ctrl = mt9t031_g_ctrl, | 734 | .g_ctrl = mt9t031_g_ctrl, |
719 | .s_ctrl = mt9t031_s_ctrl, | 735 | .s_ctrl = mt9t031_s_ctrl, |
@@ -724,19 +740,35 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | |||
724 | #endif | 740 | #endif |
725 | }; | 741 | }; |
726 | 742 | ||
743 | static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index, | ||
744 | enum v4l2_mbus_pixelcode *code) | ||
745 | { | ||
746 | if (index) | ||
747 | return -EINVAL; | ||
748 | |||
749 | *code = V4L2_MBUS_FMT_SBGGR10_1X10; | ||
750 | return 0; | ||
751 | } | ||
752 | |||
727 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | 753 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
728 | .s_stream = mt9t031_s_stream, | 754 | .s_stream = mt9t031_s_stream, |
729 | .s_fmt = mt9t031_s_fmt, | 755 | .s_mbus_fmt = mt9t031_s_fmt, |
730 | .g_fmt = mt9t031_g_fmt, | 756 | .g_mbus_fmt = mt9t031_g_fmt, |
731 | .try_fmt = mt9t031_try_fmt, | 757 | .try_mbus_fmt = mt9t031_try_fmt, |
732 | .s_crop = mt9t031_s_crop, | 758 | .s_crop = mt9t031_s_crop, |
733 | .g_crop = mt9t031_g_crop, | 759 | .g_crop = mt9t031_g_crop, |
734 | .cropcap = mt9t031_cropcap, | 760 | .cropcap = mt9t031_cropcap, |
761 | .enum_mbus_fmt = mt9t031_enum_fmt, | ||
762 | }; | ||
763 | |||
764 | static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { | ||
765 | .g_skip_top_lines = mt9t031_g_skip_top_lines, | ||
735 | }; | 766 | }; |
736 | 767 | ||
737 | static struct v4l2_subdev_ops mt9t031_subdev_ops = { | 768 | static struct v4l2_subdev_ops mt9t031_subdev_ops = { |
738 | .core = &mt9t031_subdev_core_ops, | 769 | .core = &mt9t031_subdev_core_ops, |
739 | .video = &mt9t031_subdev_video_ops, | 770 | .video = &mt9t031_subdev_video_ops, |
771 | .sensor = &mt9t031_subdev_sensor_ops, | ||
740 | }; | 772 | }; |
741 | 773 | ||
742 | static int mt9t031_probe(struct i2c_client *client, | 774 | static int mt9t031_probe(struct i2c_client *client, |
@@ -745,18 +777,16 @@ static int mt9t031_probe(struct i2c_client *client, | |||
745 | struct mt9t031 *mt9t031; | 777 | struct mt9t031 *mt9t031; |
746 | struct soc_camera_device *icd = client->dev.platform_data; | 778 | struct soc_camera_device *icd = client->dev.platform_data; |
747 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 779 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
748 | struct soc_camera_link *icl; | ||
749 | int ret; | 780 | int ret; |
750 | 781 | ||
751 | if (!icd) { | 782 | if (icd) { |
752 | dev_err(&client->dev, "MT9T031: missing soc-camera data!\n"); | 783 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
753 | return -EINVAL; | 784 | if (!icl) { |
754 | } | 785 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
786 | return -EINVAL; | ||
787 | } | ||
755 | 788 | ||
756 | icl = to_soc_camera_link(icd); | 789 | icd->ops = &mt9t031_ops; |
757 | if (!icl) { | ||
758 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | ||
759 | return -EINVAL; | ||
760 | } | 790 | } |
761 | 791 | ||
762 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | 792 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { |
@@ -771,17 +801,16 @@ static int mt9t031_probe(struct i2c_client *client, | |||
771 | 801 | ||
772 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); | 802 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
773 | 803 | ||
774 | /* Second stage probe - when a capture adapter is there */ | 804 | mt9t031->y_skip_top = 0; |
775 | icd->ops = &mt9t031_ops; | ||
776 | icd->y_skip_top = 0; | ||
777 | |||
778 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; | 805 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
779 | mt9t031->rect.top = MT9T031_ROW_SKIP; | 806 | mt9t031->rect.top = MT9T031_ROW_SKIP; |
780 | mt9t031->rect.width = MT9T031_MAX_WIDTH; | 807 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
781 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; | 808 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
782 | 809 | ||
783 | /* Simulated autoexposure. If enabled, we calculate shutter width | 810 | /* |
784 | * ourselves in the driver based on vertical blanking and frame width */ | 811 | * Simulated autoexposure. If enabled, we calculate shutter width |
812 | * ourselves in the driver based on vertical blanking and frame width | ||
813 | */ | ||
785 | mt9t031->autoexposure = 1; | 814 | mt9t031->autoexposure = 1; |
786 | 815 | ||
787 | mt9t031->xskip = 1; | 816 | mt9t031->xskip = 1; |
@@ -794,7 +823,8 @@ static int mt9t031_probe(struct i2c_client *client, | |||
794 | mt9t031_disable(client); | 823 | mt9t031_disable(client); |
795 | 824 | ||
796 | if (ret) { | 825 | if (ret) { |
797 | icd->ops = NULL; | 826 | if (icd) |
827 | icd->ops = NULL; | ||
798 | i2c_set_clientdata(client, NULL); | 828 | i2c_set_clientdata(client, NULL); |
799 | kfree(mt9t031); | 829 | kfree(mt9t031); |
800 | } | 830 | } |
@@ -807,7 +837,8 @@ static int mt9t031_remove(struct i2c_client *client) | |||
807 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 837 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
808 | struct soc_camera_device *icd = client->dev.platform_data; | 838 | struct soc_camera_device *icd = client->dev.platform_data; |
809 | 839 | ||
810 | icd->ops = NULL; | 840 | if (icd) |
841 | icd->ops = NULL; | ||
811 | i2c_set_clientdata(client, NULL); | 842 | i2c_set_clientdata(client, NULL); |
812 | client->driver = NULL; | 843 | client->driver = NULL; |
813 | kfree(mt9t031); | 844 | kfree(mt9t031); |
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c new file mode 100644 index 000000000000..fc4dd6045720 --- /dev/null +++ b/drivers/media/video/mt9t112.c | |||
@@ -0,0 +1,1177 @@ | |||
1 | /* | ||
2 | * mt9t112 Camera Driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * Based on ov772x driver, mt9m111 driver, | ||
8 | * | ||
9 | * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
10 | * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> | ||
11 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
12 | * Copyright (C) 2008 Magnus Damm | ||
13 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License version 2 as | ||
17 | * published by the Free Software Foundation. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | |||
27 | #include <media/mt9t112.h> | ||
28 | #include <media/soc_camera.h> | ||
29 | #include <media/soc_mediabus.h> | ||
30 | #include <media/v4l2-chip-ident.h> | ||
31 | #include <media/v4l2-common.h> | ||
32 | |||
33 | /* you can check PLL/clock info */ | ||
34 | /* #define EXT_CLOCK 24000000 */ | ||
35 | |||
36 | /************************************************************************ | ||
37 | |||
38 | |||
39 | macro | ||
40 | |||
41 | |||
42 | ************************************************************************/ | ||
43 | /* | ||
44 | * frame size | ||
45 | */ | ||
46 | #define MAX_WIDTH 2048 | ||
47 | #define MAX_HEIGHT 1536 | ||
48 | |||
49 | #define VGA_WIDTH 640 | ||
50 | #define VGA_HEIGHT 480 | ||
51 | |||
52 | /* | ||
53 | * macro of read/write | ||
54 | */ | ||
55 | #define ECHECKER(ret, x) \ | ||
56 | do { \ | ||
57 | (ret) = (x); \ | ||
58 | if ((ret) < 0) \ | ||
59 | return (ret); \ | ||
60 | } while (0) | ||
61 | |||
62 | #define mt9t112_reg_write(ret, client, a, b) \ | ||
63 | ECHECKER(ret, __mt9t112_reg_write(client, a, b)) | ||
64 | #define mt9t112_mcu_write(ret, client, a, b) \ | ||
65 | ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) | ||
66 | |||
67 | #define mt9t112_reg_mask_set(ret, client, a, b, c) \ | ||
68 | ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) | ||
69 | #define mt9t112_mcu_mask_set(ret, client, a, b, c) \ | ||
70 | ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) | ||
71 | |||
72 | #define mt9t112_reg_read(ret, client, a) \ | ||
73 | ECHECKER(ret, __mt9t112_reg_read(client, a)) | ||
74 | |||
75 | /* | ||
76 | * Logical address | ||
77 | */ | ||
78 | #define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) | ||
79 | #define VAR(id, offset) _VAR(id, offset, 0x0000) | ||
80 | #define VAR8(id, offset) _VAR(id, offset, 0x8000) | ||
81 | |||
82 | /************************************************************************ | ||
83 | |||
84 | |||
85 | struct | ||
86 | |||
87 | |||
88 | ************************************************************************/ | ||
89 | struct mt9t112_frame_size { | ||
90 | u16 width; | ||
91 | u16 height; | ||
92 | }; | ||
93 | |||
94 | struct mt9t112_format { | ||
95 | enum v4l2_mbus_pixelcode code; | ||
96 | enum v4l2_colorspace colorspace; | ||
97 | u16 fmt; | ||
98 | u16 order; | ||
99 | }; | ||
100 | |||
101 | struct mt9t112_priv { | ||
102 | struct v4l2_subdev subdev; | ||
103 | struct mt9t112_camera_info *info; | ||
104 | struct i2c_client *client; | ||
105 | struct soc_camera_device icd; | ||
106 | struct mt9t112_frame_size frame; | ||
107 | const struct mt9t112_format *format; | ||
108 | int model; | ||
109 | u32 flags; | ||
110 | /* for flags */ | ||
111 | #define INIT_DONE (1<<0) | ||
112 | }; | ||
113 | |||
114 | /************************************************************************ | ||
115 | |||
116 | |||
117 | supported format | ||
118 | |||
119 | |||
120 | ************************************************************************/ | ||
121 | |||
122 | static const struct mt9t112_format mt9t112_cfmts[] = { | ||
123 | { | ||
124 | .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, | ||
125 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
126 | .fmt = 1, | ||
127 | .order = 0, | ||
128 | }, { | ||
129 | .code = V4L2_MBUS_FMT_YVYU8_2X8_BE, | ||
130 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
131 | .fmt = 1, | ||
132 | .order = 1, | ||
133 | }, { | ||
134 | .code = V4L2_MBUS_FMT_YUYV8_2X8_LE, | ||
135 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
136 | .fmt = 1, | ||
137 | .order = 2, | ||
138 | }, { | ||
139 | .code = V4L2_MBUS_FMT_YVYU8_2X8_LE, | ||
140 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
141 | .fmt = 1, | ||
142 | .order = 3, | ||
143 | }, { | ||
144 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
145 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
146 | .fmt = 8, | ||
147 | .order = 2, | ||
148 | }, { | ||
149 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
150 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
151 | .fmt = 4, | ||
152 | .order = 2, | ||
153 | }, | ||
154 | }; | ||
155 | |||
156 | /************************************************************************ | ||
157 | |||
158 | |||
159 | general function | ||
160 | |||
161 | |||
162 | ************************************************************************/ | ||
163 | static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) | ||
164 | { | ||
165 | return container_of(i2c_get_clientdata(client), | ||
166 | struct mt9t112_priv, | ||
167 | subdev); | ||
168 | } | ||
169 | |||
170 | static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) | ||
171 | { | ||
172 | struct i2c_msg msg[2]; | ||
173 | u8 buf[2]; | ||
174 | int ret; | ||
175 | |||
176 | command = swab16(command); | ||
177 | |||
178 | msg[0].addr = client->addr; | ||
179 | msg[0].flags = 0; | ||
180 | msg[0].len = 2; | ||
181 | msg[0].buf = (u8 *)&command; | ||
182 | |||
183 | msg[1].addr = client->addr; | ||
184 | msg[1].flags = I2C_M_RD; | ||
185 | msg[1].len = 2; | ||
186 | msg[1].buf = buf; | ||
187 | |||
188 | /* | ||
189 | * if return value of this function is < 0, | ||
190 | * it mean error. | ||
191 | * else, under 16bit is valid data. | ||
192 | */ | ||
193 | ret = i2c_transfer(client->adapter, msg, 2); | ||
194 | if (ret < 0) | ||
195 | return ret; | ||
196 | |||
197 | memcpy(&ret, buf, 2); | ||
198 | return swab16(ret); | ||
199 | } | ||
200 | |||
201 | static int __mt9t112_reg_write(const struct i2c_client *client, | ||
202 | u16 command, u16 data) | ||
203 | { | ||
204 | struct i2c_msg msg; | ||
205 | u8 buf[4]; | ||
206 | int ret; | ||
207 | |||
208 | command = swab16(command); | ||
209 | data = swab16(data); | ||
210 | |||
211 | memcpy(buf + 0, &command, 2); | ||
212 | memcpy(buf + 2, &data, 2); | ||
213 | |||
214 | msg.addr = client->addr; | ||
215 | msg.flags = 0; | ||
216 | msg.len = 4; | ||
217 | msg.buf = buf; | ||
218 | |||
219 | /* | ||
220 | * i2c_transfer return message length, | ||
221 | * but this function should return 0 if correct case | ||
222 | */ | ||
223 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
224 | if (ret >= 0) | ||
225 | ret = 0; | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int __mt9t112_reg_mask_set(const struct i2c_client *client, | ||
231 | u16 command, | ||
232 | u16 mask, | ||
233 | u16 set) | ||
234 | { | ||
235 | int val = __mt9t112_reg_read(client, command); | ||
236 | if (val < 0) | ||
237 | return val; | ||
238 | |||
239 | val &= ~mask; | ||
240 | val |= set & mask; | ||
241 | |||
242 | return __mt9t112_reg_write(client, command, val); | ||
243 | } | ||
244 | |||
245 | /* mcu access */ | ||
246 | static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) | ||
247 | { | ||
248 | int ret; | ||
249 | |||
250 | ret = __mt9t112_reg_write(client, 0x098E, command); | ||
251 | if (ret < 0) | ||
252 | return ret; | ||
253 | |||
254 | return __mt9t112_reg_read(client, 0x0990); | ||
255 | } | ||
256 | |||
257 | static int __mt9t112_mcu_write(const struct i2c_client *client, | ||
258 | u16 command, u16 data) | ||
259 | { | ||
260 | int ret; | ||
261 | |||
262 | ret = __mt9t112_reg_write(client, 0x098E, command); | ||
263 | if (ret < 0) | ||
264 | return ret; | ||
265 | |||
266 | return __mt9t112_reg_write(client, 0x0990, data); | ||
267 | } | ||
268 | |||
269 | static int __mt9t112_mcu_mask_set(const struct i2c_client *client, | ||
270 | u16 command, | ||
271 | u16 mask, | ||
272 | u16 set) | ||
273 | { | ||
274 | int val = __mt9t112_mcu_read(client, command); | ||
275 | if (val < 0) | ||
276 | return val; | ||
277 | |||
278 | val &= ~mask; | ||
279 | val |= set & mask; | ||
280 | |||
281 | return __mt9t112_mcu_write(client, command, val); | ||
282 | } | ||
283 | |||
284 | static int mt9t112_reset(const struct i2c_client *client) | ||
285 | { | ||
286 | int ret; | ||
287 | |||
288 | mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); | ||
289 | msleep(1); | ||
290 | mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | #ifndef EXT_CLOCK | ||
296 | #define CLOCK_INFO(a, b) | ||
297 | #else | ||
298 | #define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) | ||
299 | static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) | ||
300 | { | ||
301 | int m, n, p1, p2, p3, p4, p5, p6, p7; | ||
302 | u32 vco, clk; | ||
303 | char *enable; | ||
304 | |||
305 | ext /= 1000; /* kbyte order */ | ||
306 | |||
307 | mt9t112_reg_read(n, client, 0x0012); | ||
308 | p1 = n & 0x000f; | ||
309 | n = n >> 4; | ||
310 | p2 = n & 0x000f; | ||
311 | n = n >> 4; | ||
312 | p3 = n & 0x000f; | ||
313 | |||
314 | mt9t112_reg_read(n, client, 0x002a); | ||
315 | p4 = n & 0x000f; | ||
316 | n = n >> 4; | ||
317 | p5 = n & 0x000f; | ||
318 | n = n >> 4; | ||
319 | p6 = n & 0x000f; | ||
320 | |||
321 | mt9t112_reg_read(n, client, 0x002c); | ||
322 | p7 = n & 0x000f; | ||
323 | |||
324 | mt9t112_reg_read(n, client, 0x0010); | ||
325 | m = n & 0x00ff; | ||
326 | n = (n >> 8) & 0x003f; | ||
327 | |||
328 | enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; | ||
329 | dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); | ||
330 | |||
331 | vco = 2 * m * ext / (n+1); | ||
332 | enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; | ||
333 | dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); | ||
334 | |||
335 | clk = vco / (p1+1) / (p2+1); | ||
336 | enable = (96000 < clk) ? "X" : ""; | ||
337 | dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); | ||
338 | |||
339 | clk = vco / (p3+1); | ||
340 | enable = (768000 < clk) ? "X" : ""; | ||
341 | dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); | ||
342 | |||
343 | clk = vco / (p6+1); | ||
344 | enable = (96000 < clk) ? "X" : ""; | ||
345 | dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); | ||
346 | |||
347 | clk = vco / (p5+1); | ||
348 | enable = (54000 < clk) ? "X" : ""; | ||
349 | dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); | ||
350 | |||
351 | clk = vco / (p4+1); | ||
352 | enable = (70000 < clk) ? "X" : ""; | ||
353 | dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); | ||
354 | |||
355 | clk = vco / (p7+1); | ||
356 | dev_info(&client->dev, "External sensor : %10u K\n", clk); | ||
357 | |||
358 | clk = ext / (n+1); | ||
359 | enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; | ||
360 | dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | #endif | ||
365 | |||
366 | static void mt9t112_frame_check(u32 *width, u32 *height) | ||
367 | { | ||
368 | if (*width > MAX_WIDTH) | ||
369 | *width = MAX_WIDTH; | ||
370 | |||
371 | if (*height > MAX_HEIGHT) | ||
372 | *height = MAX_HEIGHT; | ||
373 | } | ||
374 | |||
375 | static int mt9t112_set_a_frame_size(const struct i2c_client *client, | ||
376 | u16 width, | ||
377 | u16 height) | ||
378 | { | ||
379 | int ret; | ||
380 | u16 wstart = (MAX_WIDTH - width) / 2; | ||
381 | u16 hstart = (MAX_HEIGHT - height) / 2; | ||
382 | |||
383 | /* (Context A) Image Width/Height */ | ||
384 | mt9t112_mcu_write(ret, client, VAR(26, 0), width); | ||
385 | mt9t112_mcu_write(ret, client, VAR(26, 2), height); | ||
386 | |||
387 | /* (Context A) Output Width/Height */ | ||
388 | mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); | ||
389 | mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); | ||
390 | |||
391 | /* (Context A) Start Row/Column */ | ||
392 | mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); | ||
393 | mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); | ||
394 | |||
395 | /* (Context A) End Row/Column */ | ||
396 | mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); | ||
397 | mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); | ||
398 | |||
399 | mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int mt9t112_set_pll_dividers(const struct i2c_client *client, | ||
405 | u8 m, u8 n, | ||
406 | u8 p1, u8 p2, u8 p3, | ||
407 | u8 p4, u8 p5, u8 p6, | ||
408 | u8 p7) | ||
409 | { | ||
410 | int ret; | ||
411 | u16 val; | ||
412 | |||
413 | /* N/M */ | ||
414 | val = (n << 8) | | ||
415 | (m << 0); | ||
416 | mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); | ||
417 | |||
418 | /* P1/P2/P3 */ | ||
419 | val = ((p3 & 0x0F) << 8) | | ||
420 | ((p2 & 0x0F) << 4) | | ||
421 | ((p1 & 0x0F) << 0); | ||
422 | mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); | ||
423 | |||
424 | /* P4/P5/P6 */ | ||
425 | val = (0x7 << 12) | | ||
426 | ((p6 & 0x0F) << 8) | | ||
427 | ((p5 & 0x0F) << 4) | | ||
428 | ((p4 & 0x0F) << 0); | ||
429 | mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); | ||
430 | |||
431 | /* P7 */ | ||
432 | val = (0x1 << 12) | | ||
433 | ((p7 & 0x0F) << 0); | ||
434 | mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); | ||
435 | |||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | static int mt9t112_init_pll(const struct i2c_client *client) | ||
440 | { | ||
441 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
442 | int data, i, ret; | ||
443 | |||
444 | mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); | ||
445 | |||
446 | /* PLL control: BYPASS PLL = 8517 */ | ||
447 | mt9t112_reg_write(ret, client, 0x0014, 0x2145); | ||
448 | |||
449 | /* Replace these registers when new timing parameters are generated */ | ||
450 | mt9t112_set_pll_dividers(client, | ||
451 | priv->info->divider.m, | ||
452 | priv->info->divider.n, | ||
453 | priv->info->divider.p1, | ||
454 | priv->info->divider.p2, | ||
455 | priv->info->divider.p3, | ||
456 | priv->info->divider.p4, | ||
457 | priv->info->divider.p5, | ||
458 | priv->info->divider.p6, | ||
459 | priv->info->divider.p7); | ||
460 | |||
461 | /* | ||
462 | * TEST_BYPASS on | ||
463 | * PLL_ENABLE on | ||
464 | * SEL_LOCK_DET on | ||
465 | * TEST_BYPASS off | ||
466 | */ | ||
467 | mt9t112_reg_write(ret, client, 0x0014, 0x2525); | ||
468 | mt9t112_reg_write(ret, client, 0x0014, 0x2527); | ||
469 | mt9t112_reg_write(ret, client, 0x0014, 0x3427); | ||
470 | mt9t112_reg_write(ret, client, 0x0014, 0x3027); | ||
471 | |||
472 | mdelay(10); | ||
473 | |||
474 | /* | ||
475 | * PLL_BYPASS off | ||
476 | * Reference clock count | ||
477 | * I2C Master Clock Divider | ||
478 | */ | ||
479 | mt9t112_reg_write(ret, client, 0x0014, 0x3046); | ||
480 | mt9t112_reg_write(ret, client, 0x0022, 0x0190); | ||
481 | mt9t112_reg_write(ret, client, 0x3B84, 0x0212); | ||
482 | |||
483 | /* External sensor clock is PLL bypass */ | ||
484 | mt9t112_reg_write(ret, client, 0x002E, 0x0500); | ||
485 | |||
486 | mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); | ||
487 | mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); | ||
488 | |||
489 | /* MCU disabled */ | ||
490 | mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); | ||
491 | |||
492 | /* out of standby */ | ||
493 | mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); | ||
494 | |||
495 | mdelay(50); | ||
496 | |||
497 | /* | ||
498 | * Standby Workaround | ||
499 | * Disable Secondary I2C Pads | ||
500 | */ | ||
501 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
502 | mdelay(1); | ||
503 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
504 | mdelay(1); | ||
505 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
506 | mdelay(1); | ||
507 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
508 | mdelay(1); | ||
509 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
510 | mdelay(1); | ||
511 | mt9t112_reg_write(ret, client, 0x0614, 0x0001); | ||
512 | mdelay(1); | ||
513 | |||
514 | /* poll to verify out of standby. Must Poll this bit */ | ||
515 | for (i = 0; i < 100; i++) { | ||
516 | mt9t112_reg_read(data, client, 0x0018); | ||
517 | if (0x4000 & data) | ||
518 | break; | ||
519 | |||
520 | mdelay(10); | ||
521 | } | ||
522 | |||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | static int mt9t112_init_setting(const struct i2c_client *client) | ||
527 | { | ||
528 | |||
529 | int ret; | ||
530 | |||
531 | /* Adaptive Output Clock (A) */ | ||
532 | mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); | ||
533 | |||
534 | /* Read Mode (A) */ | ||
535 | mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); | ||
536 | |||
537 | /* Fine Correction (A) */ | ||
538 | mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); | ||
539 | |||
540 | /* Fine IT Min (A) */ | ||
541 | mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); | ||
542 | |||
543 | /* Fine IT Max Margin (A) */ | ||
544 | mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); | ||
545 | |||
546 | /* Base Frame Lines (A) */ | ||
547 | mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); | ||
548 | |||
549 | /* Min Line Length (A) */ | ||
550 | mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); | ||
551 | |||
552 | /* Line Length (A) */ | ||
553 | mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); | ||
554 | |||
555 | /* Adaptive Output Clock (B) */ | ||
556 | mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); | ||
557 | |||
558 | /* Row Start (B) */ | ||
559 | mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); | ||
560 | |||
561 | /* Column Start (B) */ | ||
562 | mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); | ||
563 | |||
564 | /* Row End (B) */ | ||
565 | mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); | ||
566 | |||
567 | /* Column End (B) */ | ||
568 | mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); | ||
569 | |||
570 | /* Fine Correction (B) */ | ||
571 | mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); | ||
572 | |||
573 | /* Fine IT Min (B) */ | ||
574 | mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); | ||
575 | |||
576 | /* Fine IT Max Margin (B) */ | ||
577 | mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); | ||
578 | |||
579 | /* Base Frame Lines (B) */ | ||
580 | mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); | ||
581 | |||
582 | /* Min Line Length (B) */ | ||
583 | mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); | ||
584 | |||
585 | /* Line Length (B) */ | ||
586 | mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); | ||
587 | |||
588 | /* | ||
589 | * Flicker Dectection registers | ||
590 | * This section should be replaced whenever new Timing file is generated | ||
591 | * All the following registers need to be replaced | ||
592 | * Following registers are generated from Register Wizard but user can | ||
593 | * modify them. For detail see auto flicker detection tuning | ||
594 | */ | ||
595 | |||
596 | /* FD_FDPERIOD_SELECT */ | ||
597 | mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); | ||
598 | |||
599 | /* PRI_B_CONFIG_FD_ALGO_RUN */ | ||
600 | mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); | ||
601 | |||
602 | /* PRI_A_CONFIG_FD_ALGO_RUN */ | ||
603 | mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); | ||
604 | |||
605 | /* | ||
606 | * AFD range detection tuning registers | ||
607 | */ | ||
608 | |||
609 | /* search_f1_50 */ | ||
610 | mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); | ||
611 | |||
612 | /* search_f2_50 */ | ||
613 | mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); | ||
614 | |||
615 | /* search_f1_60 */ | ||
616 | mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); | ||
617 | |||
618 | /* search_f2_60 */ | ||
619 | mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); | ||
620 | |||
621 | /* period_50Hz (A) */ | ||
622 | mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); | ||
623 | |||
624 | /* secret register by aptina */ | ||
625 | /* period_50Hz (A MSB) */ | ||
626 | mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); | ||
627 | |||
628 | /* period_60Hz (A) */ | ||
629 | mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); | ||
630 | |||
631 | /* secret register by aptina */ | ||
632 | /* period_60Hz (A MSB) */ | ||
633 | mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); | ||
634 | |||
635 | /* period_50Hz (B) */ | ||
636 | mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); | ||
637 | |||
638 | /* secret register by aptina */ | ||
639 | /* period_50Hz (B) MSB */ | ||
640 | mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); | ||
641 | |||
642 | /* period_60Hz (B) */ | ||
643 | mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); | ||
644 | |||
645 | /* secret register by aptina */ | ||
646 | /* period_60Hz (B) MSB */ | ||
647 | mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); | ||
648 | |||
649 | /* FD Mode */ | ||
650 | mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); | ||
651 | |||
652 | /* Stat_min */ | ||
653 | mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); | ||
654 | |||
655 | /* Stat_max */ | ||
656 | mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); | ||
657 | |||
658 | /* Min_amplitude */ | ||
659 | mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); | ||
660 | |||
661 | /* RX FIFO Watermark (A) */ | ||
662 | mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); | ||
663 | |||
664 | /* RX FIFO Watermark (B) */ | ||
665 | mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); | ||
666 | |||
667 | /* MCLK: 16MHz | ||
668 | * PCLK: 73MHz | ||
669 | * CorePixCLK: 36.5 MHz | ||
670 | */ | ||
671 | mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); | ||
672 | mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); | ||
673 | mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); | ||
674 | mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); | ||
675 | |||
676 | mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); | ||
677 | mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); | ||
678 | mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); | ||
679 | mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static int mt9t112_auto_focus_setting(const struct i2c_client *client) | ||
685 | { | ||
686 | int ret; | ||
687 | |||
688 | mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); | ||
689 | mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); | ||
690 | mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); | ||
691 | |||
692 | mt9t112_reg_write(ret, client, 0x0614, 0x0000); | ||
693 | |||
694 | mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); | ||
695 | mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); | ||
696 | mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); | ||
697 | mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); | ||
698 | mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); | ||
699 | mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); | ||
700 | mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); | ||
701 | mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); | ||
702 | |||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | static int mt9t112_auto_focus_trigger(const struct i2c_client *client) | ||
707 | { | ||
708 | int ret; | ||
709 | |||
710 | mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); | ||
711 | |||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | static int mt9t112_init_camera(const struct i2c_client *client) | ||
716 | { | ||
717 | int ret; | ||
718 | |||
719 | ECHECKER(ret, mt9t112_reset(client)); | ||
720 | |||
721 | ECHECKER(ret, mt9t112_init_pll(client)); | ||
722 | |||
723 | ECHECKER(ret, mt9t112_init_setting(client)); | ||
724 | |||
725 | ECHECKER(ret, mt9t112_auto_focus_setting(client)); | ||
726 | |||
727 | mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); | ||
728 | |||
729 | /* Analog setting B */ | ||
730 | mt9t112_reg_write(ret, client, 0x3084, 0x2409); | ||
731 | mt9t112_reg_write(ret, client, 0x3092, 0x0A49); | ||
732 | mt9t112_reg_write(ret, client, 0x3094, 0x4949); | ||
733 | mt9t112_reg_write(ret, client, 0x3096, 0x4950); | ||
734 | |||
735 | /* | ||
736 | * Disable adaptive clock | ||
737 | * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR | ||
738 | * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR | ||
739 | */ | ||
740 | mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); | ||
741 | mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); | ||
742 | |||
743 | /* Configure STatus in Status_before_length Format and enable header */ | ||
744 | /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ | ||
745 | mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); | ||
746 | |||
747 | /* Enable JPEG in context B */ | ||
748 | /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ | ||
749 | mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); | ||
750 | |||
751 | /* Disable Dac_TXLO */ | ||
752 | mt9t112_reg_write(ret, client, 0x316C, 0x350F); | ||
753 | |||
754 | /* Set max slew rates */ | ||
755 | mt9t112_reg_write(ret, client, 0x1E, 0x777); | ||
756 | |||
757 | return ret; | ||
758 | } | ||
759 | |||
760 | /************************************************************************ | ||
761 | |||
762 | |||
763 | soc_camera_ops | ||
764 | |||
765 | |||
766 | ************************************************************************/ | ||
767 | static int mt9t112_set_bus_param(struct soc_camera_device *icd, | ||
768 | unsigned long flags) | ||
769 | { | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) | ||
774 | { | ||
775 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
776 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
777 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
778 | unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | | ||
779 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; | ||
780 | |||
781 | flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? | ||
782 | SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; | ||
783 | |||
784 | if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) | ||
785 | flags |= SOCAM_DATAWIDTH_8; | ||
786 | else | ||
787 | flags |= SOCAM_DATAWIDTH_10; | ||
788 | |||
789 | return soc_camera_apply_sensor_flags(icl, flags); | ||
790 | } | ||
791 | |||
792 | static struct soc_camera_ops mt9t112_ops = { | ||
793 | .set_bus_param = mt9t112_set_bus_param, | ||
794 | .query_bus_param = mt9t112_query_bus_param, | ||
795 | }; | ||
796 | |||
797 | /************************************************************************ | ||
798 | |||
799 | |||
800 | v4l2_subdev_core_ops | ||
801 | |||
802 | |||
803 | ************************************************************************/ | ||
804 | static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, | ||
805 | struct v4l2_dbg_chip_ident *id) | ||
806 | { | ||
807 | struct i2c_client *client = sd->priv; | ||
808 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
809 | |||
810 | id->ident = priv->model; | ||
811 | id->revision = 0; | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
817 | static int mt9t112_g_register(struct v4l2_subdev *sd, | ||
818 | struct v4l2_dbg_register *reg) | ||
819 | { | ||
820 | struct i2c_client *client = sd->priv; | ||
821 | int ret; | ||
822 | |||
823 | reg->size = 2; | ||
824 | mt9t112_reg_read(ret, client, reg->reg); | ||
825 | |||
826 | reg->val = (__u64)ret; | ||
827 | |||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static int mt9t112_s_register(struct v4l2_subdev *sd, | ||
832 | struct v4l2_dbg_register *reg) | ||
833 | { | ||
834 | struct i2c_client *client = sd->priv; | ||
835 | int ret; | ||
836 | |||
837 | mt9t112_reg_write(ret, client, reg->reg, reg->val); | ||
838 | |||
839 | return ret; | ||
840 | } | ||
841 | #endif | ||
842 | |||
843 | static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { | ||
844 | .g_chip_ident = mt9t112_g_chip_ident, | ||
845 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
846 | .g_register = mt9t112_g_register, | ||
847 | .s_register = mt9t112_s_register, | ||
848 | #endif | ||
849 | }; | ||
850 | |||
851 | |||
852 | /************************************************************************ | ||
853 | |||
854 | |||
855 | v4l2_subdev_video_ops | ||
856 | |||
857 | |||
858 | ************************************************************************/ | ||
859 | static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | ||
860 | { | ||
861 | struct i2c_client *client = sd->priv; | ||
862 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
863 | int ret = 0; | ||
864 | |||
865 | if (!enable) { | ||
866 | /* FIXME | ||
867 | * | ||
868 | * If user selected large output size, | ||
869 | * and used it long time, | ||
870 | * mt9t112 camera will be very warm. | ||
871 | * | ||
872 | * But current driver can not stop mt9t112 camera. | ||
873 | * So, set small size here to solve this problem. | ||
874 | */ | ||
875 | mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); | ||
876 | return ret; | ||
877 | } | ||
878 | |||
879 | if (!(priv->flags & INIT_DONE)) { | ||
880 | u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & | ||
881 | priv->info->flags) ? 0x0001 : 0x0000; | ||
882 | |||
883 | ECHECKER(ret, mt9t112_init_camera(client)); | ||
884 | |||
885 | /* Invert PCLK (Data sampled on falling edge of pixclk) */ | ||
886 | mt9t112_reg_write(ret, client, 0x3C20, param); | ||
887 | |||
888 | mdelay(5); | ||
889 | |||
890 | priv->flags |= INIT_DONE; | ||
891 | } | ||
892 | |||
893 | mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); | ||
894 | mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); | ||
895 | mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); | ||
896 | |||
897 | mt9t112_set_a_frame_size(client, | ||
898 | priv->frame.width, | ||
899 | priv->frame.height); | ||
900 | |||
901 | ECHECKER(ret, mt9t112_auto_focus_trigger(client)); | ||
902 | |||
903 | dev_dbg(&client->dev, "format : %d\n", priv->format->code); | ||
904 | dev_dbg(&client->dev, "size : %d x %d\n", | ||
905 | priv->frame.width, | ||
906 | priv->frame.height); | ||
907 | |||
908 | CLOCK_INFO(client, EXT_CLOCK); | ||
909 | |||
910 | return ret; | ||
911 | } | ||
912 | |||
913 | static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, | ||
914 | enum v4l2_mbus_pixelcode code) | ||
915 | { | ||
916 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
917 | int i; | ||
918 | |||
919 | priv->format = NULL; | ||
920 | |||
921 | /* | ||
922 | * frame size check | ||
923 | */ | ||
924 | mt9t112_frame_check(&width, &height); | ||
925 | |||
926 | /* | ||
927 | * get color format | ||
928 | */ | ||
929 | for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) | ||
930 | if (mt9t112_cfmts[i].code == code) | ||
931 | break; | ||
932 | |||
933 | if (i == ARRAY_SIZE(mt9t112_cfmts)) | ||
934 | return -EINVAL; | ||
935 | |||
936 | priv->frame.width = (u16)width; | ||
937 | priv->frame.height = (u16)height; | ||
938 | |||
939 | priv->format = mt9t112_cfmts + i; | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
945 | { | ||
946 | a->bounds.left = 0; | ||
947 | a->bounds.top = 0; | ||
948 | a->bounds.width = VGA_WIDTH; | ||
949 | a->bounds.height = VGA_HEIGHT; | ||
950 | a->defrect = a->bounds; | ||
951 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
952 | a->pixelaspect.numerator = 1; | ||
953 | a->pixelaspect.denominator = 1; | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
959 | { | ||
960 | a->c.left = 0; | ||
961 | a->c.top = 0; | ||
962 | a->c.width = VGA_WIDTH; | ||
963 | a->c.height = VGA_HEIGHT; | ||
964 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
965 | |||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
970 | { | ||
971 | struct i2c_client *client = sd->priv; | ||
972 | struct v4l2_rect *rect = &a->c; | ||
973 | |||
974 | return mt9t112_set_params(client, rect->width, rect->height, | ||
975 | V4L2_MBUS_FMT_YUYV8_2X8_BE); | ||
976 | } | ||
977 | |||
978 | static int mt9t112_g_fmt(struct v4l2_subdev *sd, | ||
979 | struct v4l2_mbus_framefmt *mf) | ||
980 | { | ||
981 | struct i2c_client *client = sd->priv; | ||
982 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
983 | |||
984 | if (!priv->format) { | ||
985 | int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, | ||
986 | V4L2_MBUS_FMT_YUYV8_2X8_BE); | ||
987 | if (ret < 0) | ||
988 | return ret; | ||
989 | } | ||
990 | |||
991 | mf->width = priv->frame.width; | ||
992 | mf->height = priv->frame.height; | ||
993 | /* TODO: set colorspace */ | ||
994 | mf->code = priv->format->code; | ||
995 | mf->field = V4L2_FIELD_NONE; | ||
996 | |||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | static int mt9t112_s_fmt(struct v4l2_subdev *sd, | ||
1001 | struct v4l2_mbus_framefmt *mf) | ||
1002 | { | ||
1003 | struct i2c_client *client = sd->priv; | ||
1004 | |||
1005 | /* TODO: set colorspace */ | ||
1006 | return mt9t112_set_params(client, mf->width, mf->height, mf->code); | ||
1007 | } | ||
1008 | |||
1009 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, | ||
1010 | struct v4l2_mbus_framefmt *mf) | ||
1011 | { | ||
1012 | mt9t112_frame_check(&mf->width, &mf->height); | ||
1013 | |||
1014 | /* TODO: set colorspace */ | ||
1015 | mf->field = V4L2_FIELD_NONE; | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index, | ||
1021 | enum v4l2_mbus_pixelcode *code) | ||
1022 | { | ||
1023 | if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts)) | ||
1024 | return -EINVAL; | ||
1025 | |||
1026 | *code = mt9t112_cfmts[index].code; | ||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { | ||
1031 | .s_stream = mt9t112_s_stream, | ||
1032 | .g_mbus_fmt = mt9t112_g_fmt, | ||
1033 | .s_mbus_fmt = mt9t112_s_fmt, | ||
1034 | .try_mbus_fmt = mt9t112_try_fmt, | ||
1035 | .cropcap = mt9t112_cropcap, | ||
1036 | .g_crop = mt9t112_g_crop, | ||
1037 | .s_crop = mt9t112_s_crop, | ||
1038 | .enum_mbus_fmt = mt9t112_enum_fmt, | ||
1039 | }; | ||
1040 | |||
1041 | /************************************************************************ | ||
1042 | |||
1043 | |||
1044 | i2c driver | ||
1045 | |||
1046 | |||
1047 | ************************************************************************/ | ||
1048 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { | ||
1049 | .core = &mt9t112_subdev_core_ops, | ||
1050 | .video = &mt9t112_subdev_video_ops, | ||
1051 | }; | ||
1052 | |||
1053 | static int mt9t112_camera_probe(struct soc_camera_device *icd, | ||
1054 | struct i2c_client *client) | ||
1055 | { | ||
1056 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
1057 | const char *devname; | ||
1058 | int chipid; | ||
1059 | |||
1060 | /* | ||
1061 | * We must have a parent by now. And it cannot be a wrong one. | ||
1062 | * So this entire test is completely redundant. | ||
1063 | */ | ||
1064 | if (!icd->dev.parent || | ||
1065 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | ||
1066 | return -ENODEV; | ||
1067 | |||
1068 | /* | ||
1069 | * check and show chip ID | ||
1070 | */ | ||
1071 | mt9t112_reg_read(chipid, client, 0x0000); | ||
1072 | |||
1073 | switch (chipid) { | ||
1074 | case 0x2680: | ||
1075 | devname = "mt9t111"; | ||
1076 | priv->model = V4L2_IDENT_MT9T111; | ||
1077 | break; | ||
1078 | case 0x2682: | ||
1079 | devname = "mt9t112"; | ||
1080 | priv->model = V4L2_IDENT_MT9T112; | ||
1081 | break; | ||
1082 | default: | ||
1083 | dev_err(&client->dev, "Product ID error %04x\n", chipid); | ||
1084 | return -ENODEV; | ||
1085 | } | ||
1086 | |||
1087 | dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); | ||
1088 | |||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static int mt9t112_probe(struct i2c_client *client, | ||
1093 | const struct i2c_device_id *did) | ||
1094 | { | ||
1095 | struct mt9t112_priv *priv; | ||
1096 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1097 | struct soc_camera_link *icl; | ||
1098 | int ret; | ||
1099 | |||
1100 | if (!icd) { | ||
1101 | dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); | ||
1102 | return -EINVAL; | ||
1103 | } | ||
1104 | |||
1105 | icl = to_soc_camera_link(icd); | ||
1106 | if (!icl || !icl->priv) | ||
1107 | return -EINVAL; | ||
1108 | |||
1109 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1110 | if (!priv) | ||
1111 | return -ENOMEM; | ||
1112 | |||
1113 | priv->info = icl->priv; | ||
1114 | |||
1115 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); | ||
1116 | |||
1117 | icd->ops = &mt9t112_ops; | ||
1118 | |||
1119 | ret = mt9t112_camera_probe(icd, client); | ||
1120 | if (ret) { | ||
1121 | icd->ops = NULL; | ||
1122 | i2c_set_clientdata(client, NULL); | ||
1123 | kfree(priv); | ||
1124 | } | ||
1125 | |||
1126 | return ret; | ||
1127 | } | ||
1128 | |||
1129 | static int mt9t112_remove(struct i2c_client *client) | ||
1130 | { | ||
1131 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
1132 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1133 | |||
1134 | icd->ops = NULL; | ||
1135 | i2c_set_clientdata(client, NULL); | ||
1136 | kfree(priv); | ||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static const struct i2c_device_id mt9t112_id[] = { | ||
1141 | { "mt9t112", 0 }, | ||
1142 | { } | ||
1143 | }; | ||
1144 | MODULE_DEVICE_TABLE(i2c, mt9t112_id); | ||
1145 | |||
1146 | static struct i2c_driver mt9t112_i2c_driver = { | ||
1147 | .driver = { | ||
1148 | .name = "mt9t112", | ||
1149 | }, | ||
1150 | .probe = mt9t112_probe, | ||
1151 | .remove = mt9t112_remove, | ||
1152 | .id_table = mt9t112_id, | ||
1153 | }; | ||
1154 | |||
1155 | /************************************************************************ | ||
1156 | |||
1157 | |||
1158 | module function | ||
1159 | |||
1160 | |||
1161 | ************************************************************************/ | ||
1162 | static int __init mt9t112_module_init(void) | ||
1163 | { | ||
1164 | return i2c_add_driver(&mt9t112_i2c_driver); | ||
1165 | } | ||
1166 | |||
1167 | static void __exit mt9t112_module_exit(void) | ||
1168 | { | ||
1169 | i2c_del_driver(&mt9t112_i2c_driver); | ||
1170 | } | ||
1171 | |||
1172 | module_init(mt9t112_module_init); | ||
1173 | module_exit(mt9t112_module_exit); | ||
1174 | |||
1175 | MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); | ||
1176 | MODULE_AUTHOR("Kuninori Morimoto"); | ||
1177 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 995607f9d3ba..91df7ec91fb6 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -18,9 +18,11 @@ | |||
18 | #include <media/v4l2-chip-ident.h> | 18 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | 20 | ||
21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 21 | /* |
22 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | ||
22 | * The platform has to define ctruct i2c_board_info objects and link to them | 23 | * The platform has to define ctruct i2c_board_info objects and link to them |
23 | * from struct soc_camera_link */ | 24 | * from struct soc_camera_link |
25 | */ | ||
24 | 26 | ||
25 | static char *sensor_type; | 27 | static char *sensor_type; |
26 | module_param(sensor_type, charp, S_IRUGO); | 28 | module_param(sensor_type, charp, S_IRUGO); |
@@ -62,41 +64,49 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
62 | #define MT9V022_COLUMN_SKIP 1 | 64 | #define MT9V022_COLUMN_SKIP 1 |
63 | #define MT9V022_ROW_SKIP 4 | 65 | #define MT9V022_ROW_SKIP 4 |
64 | 66 | ||
65 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { | 67 | /* MT9V022 has only one fixed colorspace per pixelcode */ |
66 | /* Order important: first natively supported, | 68 | struct mt9v022_datafmt { |
67 | * second supported with a GPIO extender */ | 69 | enum v4l2_mbus_pixelcode code; |
68 | { | 70 | enum v4l2_colorspace colorspace; |
69 | .name = "Bayer (sRGB) 10 bit", | 71 | }; |
70 | .depth = 10, | 72 | |
71 | .fourcc = V4L2_PIX_FMT_SBGGR16, | 73 | /* Find a data format by a pixel code in an array */ |
72 | .colorspace = V4L2_COLORSPACE_SRGB, | 74 | static const struct mt9v022_datafmt *mt9v022_find_datafmt( |
73 | }, { | 75 | enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, |
74 | .name = "Bayer (sRGB) 8 bit", | 76 | int n) |
75 | .depth = 8, | 77 | { |
76 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 78 | int i; |
77 | .colorspace = V4L2_COLORSPACE_SRGB, | 79 | for (i = 0; i < n; i++) |
78 | } | 80 | if (fmt[i].code == code) |
81 | return fmt + i; | ||
82 | |||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { | ||
87 | /* | ||
88 | * Order important: first natively supported, | ||
89 | * second supported with a GPIO extender | ||
90 | */ | ||
91 | {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, | ||
92 | {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, | ||
79 | }; | 93 | }; |
80 | 94 | ||
81 | static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { | 95 | static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { |
82 | /* Order important - see above */ | 96 | /* Order important - see above */ |
83 | { | 97 | {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, |
84 | .name = "Monochrome 10 bit", | 98 | {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, |
85 | .depth = 10, | ||
86 | .fourcc = V4L2_PIX_FMT_Y16, | ||
87 | }, { | ||
88 | .name = "Monochrome 8 bit", | ||
89 | .depth = 8, | ||
90 | .fourcc = V4L2_PIX_FMT_GREY, | ||
91 | }, | ||
92 | }; | 99 | }; |
93 | 100 | ||
94 | struct mt9v022 { | 101 | struct mt9v022 { |
95 | struct v4l2_subdev subdev; | 102 | struct v4l2_subdev subdev; |
96 | struct v4l2_rect rect; /* Sensor window */ | 103 | struct v4l2_rect rect; /* Sensor window */ |
97 | __u32 fourcc; | 104 | const struct mt9v022_datafmt *fmt; |
105 | const struct mt9v022_datafmt *fmts; | ||
106 | int num_fmts; | ||
98 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 107 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
99 | u16 chip_control; | 108 | u16 chip_control; |
109 | unsigned short y_skip_top; /* Lines to skip at the top */ | ||
100 | }; | 110 | }; |
101 | 111 | ||
102 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) | 112 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) |
@@ -143,9 +153,11 @@ static int mt9v022_init(struct i2c_client *client) | |||
143 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 153 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
144 | int ret; | 154 | int ret; |
145 | 155 | ||
146 | /* Almost the default mode: master, parallel, simultaneous, and an | 156 | /* |
157 | * Almost the default mode: master, parallel, simultaneous, and an | ||
147 | * undocumented bit 0x200, which is present in table 7, but not in 8, | 158 | * undocumented bit 0x200, which is present in table 7, but not in 8, |
148 | * plus snapshot mode to disable scan for now */ | 159 | * plus snapshot mode to disable scan for now |
160 | */ | ||
149 | mt9v022->chip_control |= 0x10; | 161 | mt9v022->chip_control |= 0x10; |
150 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | 162 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); |
151 | if (!ret) | 163 | if (!ret) |
@@ -265,12 +277,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
265 | struct i2c_client *client = sd->priv; | 277 | struct i2c_client *client = sd->priv; |
266 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 278 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
267 | struct v4l2_rect rect = a->c; | 279 | struct v4l2_rect rect = a->c; |
268 | struct soc_camera_device *icd = client->dev.platform_data; | ||
269 | int ret; | 280 | int ret; |
270 | 281 | ||
271 | /* Bayer format - even size lengths */ | 282 | /* Bayer format - even size lengths */ |
272 | if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 || | 283 | if (mt9v022->fmts == mt9v022_colour_fmts) { |
273 | mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) { | ||
274 | rect.width = ALIGN(rect.width, 2); | 284 | rect.width = ALIGN(rect.width, 2); |
275 | rect.height = ALIGN(rect.height, 2); | 285 | rect.height = ALIGN(rect.height, 2); |
276 | /* Let the user play with the starting pixel */ | 286 | /* Let the user play with the starting pixel */ |
@@ -287,10 +297,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
287 | if (ret >= 0) { | 297 | if (ret >= 0) { |
288 | if (ret & 1) /* Autoexposure */ | 298 | if (ret & 1) /* Autoexposure */ |
289 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, | 299 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, |
290 | rect.height + icd->y_skip_top + 43); | 300 | rect.height + mt9v022->y_skip_top + 43); |
291 | else | 301 | else |
292 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 302 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
293 | rect.height + icd->y_skip_top + 43); | 303 | rect.height + mt9v022->y_skip_top + 43); |
294 | } | 304 | } |
295 | /* Setup frame format: defaults apart from width and height */ | 305 | /* Setup frame format: defaults apart from width and height */ |
296 | if (!ret) | 306 | if (!ret) |
@@ -298,8 +308,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
298 | if (!ret) | 308 | if (!ret) |
299 | ret = reg_write(client, MT9V022_ROW_START, rect.top); | 309 | ret = reg_write(client, MT9V022_ROW_START, rect.top); |
300 | if (!ret) | 310 | if (!ret) |
301 | /* Default 94, Phytec driver says: | 311 | /* |
302 | * "width + horizontal blank >= 660" */ | 312 | * Default 94, Phytec driver says: |
313 | * "width + horizontal blank >= 660" | ||
314 | */ | ||
303 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, | 315 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, |
304 | rect.width > 660 - 43 ? 43 : | 316 | rect.width > 660 - 43 ? 43 : |
305 | 660 - rect.width); | 317 | 660 - rect.width); |
@@ -309,7 +321,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
309 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); | 321 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); |
310 | if (!ret) | 322 | if (!ret) |
311 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, | 323 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, |
312 | rect.height + icd->y_skip_top); | 324 | rect.height + mt9v022->y_skip_top); |
313 | 325 | ||
314 | if (ret < 0) | 326 | if (ret < 0) |
315 | return ret; | 327 | return ret; |
@@ -346,46 +358,48 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
346 | return 0; | 358 | return 0; |
347 | } | 359 | } |
348 | 360 | ||
349 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 361 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, |
362 | struct v4l2_mbus_framefmt *mf) | ||
350 | { | 363 | { |
351 | struct i2c_client *client = sd->priv; | 364 | struct i2c_client *client = sd->priv; |
352 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 365 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
353 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
354 | 366 | ||
355 | pix->width = mt9v022->rect.width; | 367 | mf->width = mt9v022->rect.width; |
356 | pix->height = mt9v022->rect.height; | 368 | mf->height = mt9v022->rect.height; |
357 | pix->pixelformat = mt9v022->fourcc; | 369 | mf->code = mt9v022->fmt->code; |
358 | pix->field = V4L2_FIELD_NONE; | 370 | mf->colorspace = mt9v022->fmt->colorspace; |
359 | pix->colorspace = V4L2_COLORSPACE_SRGB; | 371 | mf->field = V4L2_FIELD_NONE; |
360 | 372 | ||
361 | return 0; | 373 | return 0; |
362 | } | 374 | } |
363 | 375 | ||
364 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 376 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, |
377 | struct v4l2_mbus_framefmt *mf) | ||
365 | { | 378 | { |
366 | struct i2c_client *client = sd->priv; | 379 | struct i2c_client *client = sd->priv; |
367 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 380 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
368 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
369 | struct v4l2_crop a = { | 381 | struct v4l2_crop a = { |
370 | .c = { | 382 | .c = { |
371 | .left = mt9v022->rect.left, | 383 | .left = mt9v022->rect.left, |
372 | .top = mt9v022->rect.top, | 384 | .top = mt9v022->rect.top, |
373 | .width = pix->width, | 385 | .width = mf->width, |
374 | .height = pix->height, | 386 | .height = mf->height, |
375 | }, | 387 | }, |
376 | }; | 388 | }; |
377 | int ret; | 389 | int ret; |
378 | 390 | ||
379 | /* The caller provides a supported format, as verified per call to | 391 | /* |
380 | * icd->try_fmt(), datawidth is from our supported format list */ | 392 | * The caller provides a supported format, as verified per call to |
381 | switch (pix->pixelformat) { | 393 | * icd->try_fmt(), datawidth is from our supported format list |
382 | case V4L2_PIX_FMT_GREY: | 394 | */ |
383 | case V4L2_PIX_FMT_Y16: | 395 | switch (mf->code) { |
396 | case V4L2_MBUS_FMT_GREY8_1X8: | ||
397 | case V4L2_MBUS_FMT_Y10_1X10: | ||
384 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) | 398 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) |
385 | return -EINVAL; | 399 | return -EINVAL; |
386 | break; | 400 | break; |
387 | case V4L2_PIX_FMT_SBGGR8: | 401 | case V4L2_MBUS_FMT_SBGGR8_1X8: |
388 | case V4L2_PIX_FMT_SBGGR16: | 402 | case V4L2_MBUS_FMT_SBGGR10_1X10: |
389 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) | 403 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) |
390 | return -EINVAL; | 404 | return -EINVAL; |
391 | break; | 405 | break; |
@@ -399,26 +413,38 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
399 | /* No support for scaling on this camera, just crop. */ | 413 | /* No support for scaling on this camera, just crop. */ |
400 | ret = mt9v022_s_crop(sd, &a); | 414 | ret = mt9v022_s_crop(sd, &a); |
401 | if (!ret) { | 415 | if (!ret) { |
402 | pix->width = mt9v022->rect.width; | 416 | mf->width = mt9v022->rect.width; |
403 | pix->height = mt9v022->rect.height; | 417 | mf->height = mt9v022->rect.height; |
404 | mt9v022->fourcc = pix->pixelformat; | 418 | mt9v022->fmt = mt9v022_find_datafmt(mf->code, |
419 | mt9v022->fmts, mt9v022->num_fmts); | ||
420 | mf->colorspace = mt9v022->fmt->colorspace; | ||
405 | } | 421 | } |
406 | 422 | ||
407 | return ret; | 423 | return ret; |
408 | } | 424 | } |
409 | 425 | ||
410 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 426 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, |
427 | struct v4l2_mbus_framefmt *mf) | ||
411 | { | 428 | { |
412 | struct i2c_client *client = sd->priv; | 429 | struct i2c_client *client = sd->priv; |
413 | struct soc_camera_device *icd = client->dev.platform_data; | 430 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
414 | struct v4l2_pix_format *pix = &f->fmt.pix; | 431 | const struct mt9v022_datafmt *fmt; |
415 | int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | 432 | int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || |
416 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | 433 | mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; |
417 | 434 | ||
418 | v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH, | 435 | v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, |
419 | MT9V022_MAX_WIDTH, align, | 436 | MT9V022_MAX_WIDTH, align, |
420 | &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top, | 437 | &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, |
421 | MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0); | 438 | MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); |
439 | |||
440 | fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, | ||
441 | mt9v022->num_fmts); | ||
442 | if (!fmt) { | ||
443 | fmt = mt9v022->fmt; | ||
444 | mf->code = fmt->code; | ||
445 | } | ||
446 | |||
447 | mf->colorspace = fmt->colorspace; | ||
422 | 448 | ||
423 | return 0; | 449 | return 0; |
424 | } | 450 | } |
@@ -635,8 +661,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
635 | 48 + range / 2) / range + 16; | 661 | 48 + range / 2) / range + 16; |
636 | if (gain >= 32) | 662 | if (gain >= 32) |
637 | gain &= ~1; | 663 | gain &= ~1; |
638 | /* The user wants to set gain manually, hope, she | 664 | /* |
639 | * knows, what she's doing... Switch AGC off. */ | 665 | * The user wants to set gain manually, hope, she |
666 | * knows, what she's doing... Switch AGC off. | ||
667 | */ | ||
640 | 668 | ||
641 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 669 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
642 | return -EIO; | 670 | return -EIO; |
@@ -655,8 +683,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
655 | unsigned long range = qctrl->maximum - qctrl->minimum; | 683 | unsigned long range = qctrl->maximum - qctrl->minimum; |
656 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * | 684 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * |
657 | 479 + range / 2) / range + 1; | 685 | 479 + range / 2) / range + 1; |
658 | /* The user wants to set shutter width manually, hope, | 686 | /* |
659 | * she knows, what she's doing... Switch AEC off. */ | 687 | * The user wants to set shutter width manually, hope, |
688 | * she knows, what she's doing... Switch AEC off. | ||
689 | */ | ||
660 | 690 | ||
661 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 691 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) |
662 | return -EIO; | 692 | return -EIO; |
@@ -689,8 +719,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
689 | return 0; | 719 | return 0; |
690 | } | 720 | } |
691 | 721 | ||
692 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 722 | /* |
693 | * this wasn't our capture interface, so, we wait for the right one */ | 723 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
724 | * this wasn't our capture interface, so, we wait for the right one | ||
725 | */ | ||
694 | static int mt9v022_video_probe(struct soc_camera_device *icd, | 726 | static int mt9v022_video_probe(struct soc_camera_device *icd, |
695 | struct i2c_client *client) | 727 | struct i2c_client *client) |
696 | { | 728 | { |
@@ -733,17 +765,17 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, | |||
733 | !strcmp("color", sensor_type))) { | 765 | !strcmp("color", sensor_type))) { |
734 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); | 766 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); |
735 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; | 767 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; |
736 | icd->formats = mt9v022_colour_formats; | 768 | mt9v022->fmts = mt9v022_colour_fmts; |
737 | } else { | 769 | } else { |
738 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); | 770 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); |
739 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; | 771 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; |
740 | icd->formats = mt9v022_monochrome_formats; | 772 | mt9v022->fmts = mt9v022_monochrome_fmts; |
741 | } | 773 | } |
742 | 774 | ||
743 | if (ret < 0) | 775 | if (ret < 0) |
744 | goto ei2c; | 776 | goto ei2c; |
745 | 777 | ||
746 | icd->num_formats = 0; | 778 | mt9v022->num_fmts = 0; |
747 | 779 | ||
748 | /* | 780 | /* |
749 | * This is a 10bit sensor, so by default we only allow 10bit. | 781 | * This is a 10bit sensor, so by default we only allow 10bit. |
@@ -756,14 +788,14 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, | |||
756 | flags = SOCAM_DATAWIDTH_10; | 788 | flags = SOCAM_DATAWIDTH_10; |
757 | 789 | ||
758 | if (flags & SOCAM_DATAWIDTH_10) | 790 | if (flags & SOCAM_DATAWIDTH_10) |
759 | icd->num_formats++; | 791 | mt9v022->num_fmts++; |
760 | else | 792 | else |
761 | icd->formats++; | 793 | mt9v022->fmts++; |
762 | 794 | ||
763 | if (flags & SOCAM_DATAWIDTH_8) | 795 | if (flags & SOCAM_DATAWIDTH_8) |
764 | icd->num_formats++; | 796 | mt9v022->num_fmts++; |
765 | 797 | ||
766 | mt9v022->fourcc = icd->formats->fourcc; | 798 | mt9v022->fmt = &mt9v022->fmts[0]; |
767 | 799 | ||
768 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", | 800 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", |
769 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? | 801 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? |
@@ -787,6 +819,16 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) | |||
787 | icl->free_bus(icl); | 819 | icl->free_bus(icl); |
788 | } | 820 | } |
789 | 821 | ||
822 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | ||
823 | { | ||
824 | struct i2c_client *client = sd->priv; | ||
825 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
826 | |||
827 | *lines = mt9v022->y_skip_top; | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
790 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 832 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
791 | .g_ctrl = mt9v022_g_ctrl, | 833 | .g_ctrl = mt9v022_g_ctrl, |
792 | .s_ctrl = mt9v022_s_ctrl, | 834 | .s_ctrl = mt9v022_s_ctrl, |
@@ -797,19 +839,38 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | |||
797 | #endif | 839 | #endif |
798 | }; | 840 | }; |
799 | 841 | ||
842 | static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index, | ||
843 | enum v4l2_mbus_pixelcode *code) | ||
844 | { | ||
845 | struct i2c_client *client = sd->priv; | ||
846 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
847 | |||
848 | if ((unsigned int)index >= mt9v022->num_fmts) | ||
849 | return -EINVAL; | ||
850 | |||
851 | *code = mt9v022->fmts[index].code; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
800 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 855 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
801 | .s_stream = mt9v022_s_stream, | 856 | .s_stream = mt9v022_s_stream, |
802 | .s_fmt = mt9v022_s_fmt, | 857 | .s_mbus_fmt = mt9v022_s_fmt, |
803 | .g_fmt = mt9v022_g_fmt, | 858 | .g_mbus_fmt = mt9v022_g_fmt, |
804 | .try_fmt = mt9v022_try_fmt, | 859 | .try_mbus_fmt = mt9v022_try_fmt, |
805 | .s_crop = mt9v022_s_crop, | 860 | .s_crop = mt9v022_s_crop, |
806 | .g_crop = mt9v022_g_crop, | 861 | .g_crop = mt9v022_g_crop, |
807 | .cropcap = mt9v022_cropcap, | 862 | .cropcap = mt9v022_cropcap, |
863 | .enum_mbus_fmt = mt9v022_enum_fmt, | ||
864 | }; | ||
865 | |||
866 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | ||
867 | .g_skip_top_lines = mt9v022_g_skip_top_lines, | ||
808 | }; | 868 | }; |
809 | 869 | ||
810 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { | 870 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { |
811 | .core = &mt9v022_subdev_core_ops, | 871 | .core = &mt9v022_subdev_core_ops, |
812 | .video = &mt9v022_subdev_video_ops, | 872 | .video = &mt9v022_subdev_video_ops, |
873 | .sensor = &mt9v022_subdev_sensor_ops, | ||
813 | }; | 874 | }; |
814 | 875 | ||
815 | static int mt9v022_probe(struct i2c_client *client, | 876 | static int mt9v022_probe(struct i2c_client *client, |
@@ -851,8 +912,7 @@ static int mt9v022_probe(struct i2c_client *client, | |||
851 | * MT9V022 _really_ corrupts the first read out line. | 912 | * MT9V022 _really_ corrupts the first read out line. |
852 | * TODO: verify on i.MX31 | 913 | * TODO: verify on i.MX31 |
853 | */ | 914 | */ |
854 | icd->y_skip_top = 1; | 915 | mt9v022->y_skip_top = 1; |
855 | |||
856 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; | 916 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; |
857 | mt9v022->rect.top = MT9V022_ROW_SKIP; | 917 | mt9v022->rect.top = MT9V022_ROW_SKIP; |
858 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | 918 | mt9v022->rect.width = MT9V022_MAX_WIDTH; |
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 72802291e812..2ba14fb5b031 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
38 | #include <media/v4l2-dev.h> | 38 | #include <media/v4l2-dev.h> |
39 | #include <media/videobuf-dma-contig.h> | 39 | #include <media/videobuf-dma-contig.h> |
40 | #include <media/soc_mediabus.h> | ||
40 | 41 | ||
41 | #include <asm/dma.h> | 42 | #include <asm/dma.h> |
42 | #include <asm/fiq.h> | 43 | #include <asm/fiq.h> |
@@ -94,14 +95,16 @@ | |||
94 | /* buffer for one video frame */ | 95 | /* buffer for one video frame */ |
95 | struct mx1_buffer { | 96 | struct mx1_buffer { |
96 | /* common v4l buffer stuff -- must be first */ | 97 | /* common v4l buffer stuff -- must be first */ |
97 | struct videobuf_buffer vb; | 98 | struct videobuf_buffer vb; |
98 | const struct soc_camera_data_format *fmt; | 99 | enum v4l2_mbus_pixelcode code; |
99 | int inwork; | 100 | int inwork; |
100 | }; | 101 | }; |
101 | 102 | ||
102 | /* i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor | 103 | /* |
104 | * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor | ||
103 | * Interface. If anyone ever builds hardware to enable more than | 105 | * Interface. If anyone ever builds hardware to enable more than |
104 | * one camera, they will have to modify this driver too */ | 106 | * one camera, they will have to modify this driver too |
107 | */ | ||
105 | struct mx1_camera_dev { | 108 | struct mx1_camera_dev { |
106 | struct soc_camera_host soc_host; | 109 | struct soc_camera_host soc_host; |
107 | struct soc_camera_device *icd; | 110 | struct soc_camera_device *icd; |
@@ -126,9 +129,13 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
126 | unsigned int *size) | 129 | unsigned int *size) |
127 | { | 130 | { |
128 | struct soc_camera_device *icd = vq->priv_data; | 131 | struct soc_camera_device *icd = vq->priv_data; |
132 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
133 | icd->current_fmt->host_fmt); | ||
134 | |||
135 | if (bytes_per_line < 0) | ||
136 | return bytes_per_line; | ||
129 | 137 | ||
130 | *size = icd->user_width * icd->user_height * | 138 | *size = bytes_per_line * icd->user_height; |
131 | ((icd->current_fmt->depth + 7) >> 3); | ||
132 | 139 | ||
133 | if (!*count) | 140 | if (!*count) |
134 | *count = 32; | 141 | *count = 32; |
@@ -151,8 +158,10 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) | |||
151 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 158 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
152 | vb, vb->baddr, vb->bsize); | 159 | vb, vb->baddr, vb->bsize); |
153 | 160 | ||
154 | /* This waits until this buffer is out of danger, i.e., until it is no | 161 | /* |
155 | * longer in STATE_QUEUED or STATE_ACTIVE */ | 162 | * This waits until this buffer is out of danger, i.e., until it is no |
163 | * longer in STATE_QUEUED or STATE_ACTIVE | ||
164 | */ | ||
156 | videobuf_waiton(vb, 0, 0); | 165 | videobuf_waiton(vb, 0, 0); |
157 | videobuf_dma_contig_free(vq, vb); | 166 | videobuf_dma_contig_free(vq, vb); |
158 | 167 | ||
@@ -165,6 +174,11 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, | |||
165 | struct soc_camera_device *icd = vq->priv_data; | 174 | struct soc_camera_device *icd = vq->priv_data; |
166 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | 175 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); |
167 | int ret; | 176 | int ret; |
177 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
178 | icd->current_fmt->host_fmt); | ||
179 | |||
180 | if (bytes_per_line < 0) | ||
181 | return bytes_per_line; | ||
168 | 182 | ||
169 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 183 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
170 | vb, vb->baddr, vb->bsize); | 184 | vb, vb->baddr, vb->bsize); |
@@ -174,22 +188,24 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, | |||
174 | 188 | ||
175 | BUG_ON(NULL == icd->current_fmt); | 189 | BUG_ON(NULL == icd->current_fmt); |
176 | 190 | ||
177 | /* I think, in buf_prepare you only have to protect global data, | 191 | /* |
178 | * the actual buffer is yours */ | 192 | * I think, in buf_prepare you only have to protect global data, |
193 | * the actual buffer is yours | ||
194 | */ | ||
179 | buf->inwork = 1; | 195 | buf->inwork = 1; |
180 | 196 | ||
181 | if (buf->fmt != icd->current_fmt || | 197 | if (buf->code != icd->current_fmt->code || |
182 | vb->width != icd->user_width || | 198 | vb->width != icd->user_width || |
183 | vb->height != icd->user_height || | 199 | vb->height != icd->user_height || |
184 | vb->field != field) { | 200 | vb->field != field) { |
185 | buf->fmt = icd->current_fmt; | 201 | buf->code = icd->current_fmt->code; |
186 | vb->width = icd->user_width; | 202 | vb->width = icd->user_width; |
187 | vb->height = icd->user_height; | 203 | vb->height = icd->user_height; |
188 | vb->field = field; | 204 | vb->field = field; |
189 | vb->state = VIDEOBUF_NEEDS_INIT; | 205 | vb->state = VIDEOBUF_NEEDS_INIT; |
190 | } | 206 | } |
191 | 207 | ||
192 | vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); | 208 | vb->size = bytes_per_line * vb->height; |
193 | if (0 != vb->baddr && vb->bsize < vb->size) { | 209 | if (0 != vb->baddr && vb->bsize < vb->size) { |
194 | ret = -EINVAL; | 210 | ret = -EINVAL; |
195 | goto out; | 211 | goto out; |
@@ -381,8 +397,10 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) | |||
381 | 397 | ||
382 | lcdclk = clk_get_rate(pcdev->clk); | 398 | lcdclk = clk_get_rate(pcdev->clk); |
383 | 399 | ||
384 | /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here | 400 | /* |
385 | * they get a nice Oops */ | 401 | * We verify platform_mclk_10khz != 0, so if anyone breaks it, here |
402 | * they get a nice Oops | ||
403 | */ | ||
386 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; | 404 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; |
387 | 405 | ||
388 | dev_dbg(pcdev->icd->dev.parent, | 406 | dev_dbg(pcdev->icd->dev.parent, |
@@ -420,8 +438,10 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) | |||
420 | clk_disable(pcdev->clk); | 438 | clk_disable(pcdev->clk); |
421 | } | 439 | } |
422 | 440 | ||
423 | /* The following two functions absolutely depend on the fact, that | 441 | /* |
424 | * there can be only one camera on i.MX1/i.MXL camera sensor interface */ | 442 | * The following two functions absolutely depend on the fact, that |
443 | * there can be only one camera on i.MX1/i.MXL camera sensor interface | ||
444 | */ | ||
425 | static int mx1_camera_add_device(struct soc_camera_device *icd) | 445 | static int mx1_camera_add_device(struct soc_camera_device *icd) |
426 | { | 446 | { |
427 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 447 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
@@ -487,12 +507,10 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
487 | 507 | ||
488 | /* MX1 supports only 8bit buswidth */ | 508 | /* MX1 supports only 8bit buswidth */ |
489 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 509 | common_flags = soc_camera_bus_param_compatible(camera_flags, |
490 | CSI_BUS_FLAGS); | 510 | CSI_BUS_FLAGS); |
491 | if (!common_flags) | 511 | if (!common_flags) |
492 | return -EINVAL; | 512 | return -EINVAL; |
493 | 513 | ||
494 | icd->buswidth = 8; | ||
495 | |||
496 | /* Make choises, based on platform choice */ | 514 | /* Make choises, based on platform choice */ |
497 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 515 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && |
498 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 516 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { |
@@ -545,7 +563,8 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, | |||
545 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 563 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
546 | const struct soc_camera_format_xlate *xlate; | 564 | const struct soc_camera_format_xlate *xlate; |
547 | struct v4l2_pix_format *pix = &f->fmt.pix; | 565 | struct v4l2_pix_format *pix = &f->fmt.pix; |
548 | int ret; | 566 | struct v4l2_mbus_framefmt mf; |
567 | int ret, buswidth; | ||
549 | 568 | ||
550 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 569 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
551 | if (!xlate) { | 570 | if (!xlate) { |
@@ -554,12 +573,33 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, | |||
554 | return -EINVAL; | 573 | return -EINVAL; |
555 | } | 574 | } |
556 | 575 | ||
557 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 576 | buswidth = xlate->host_fmt->bits_per_sample; |
558 | if (!ret) { | 577 | if (buswidth > 8) { |
559 | icd->buswidth = xlate->buswidth; | 578 | dev_warn(icd->dev.parent, |
560 | icd->current_fmt = xlate->host_fmt; | 579 | "bits-per-sample %d for format %x unsupported\n", |
580 | buswidth, pix->pixelformat); | ||
581 | return -EINVAL; | ||
561 | } | 582 | } |
562 | 583 | ||
584 | mf.width = pix->width; | ||
585 | mf.height = pix->height; | ||
586 | mf.field = pix->field; | ||
587 | mf.colorspace = pix->colorspace; | ||
588 | mf.code = xlate->code; | ||
589 | |||
590 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
591 | if (ret < 0) | ||
592 | return ret; | ||
593 | |||
594 | if (mf.code != xlate->code) | ||
595 | return -EINVAL; | ||
596 | |||
597 | pix->width = mf.width; | ||
598 | pix->height = mf.height; | ||
599 | pix->field = mf.field; | ||
600 | pix->colorspace = mf.colorspace; | ||
601 | icd->current_fmt = xlate; | ||
602 | |||
563 | return ret; | 603 | return ret; |
564 | } | 604 | } |
565 | 605 | ||
@@ -567,10 +607,36 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd, | |||
567 | struct v4l2_format *f) | 607 | struct v4l2_format *f) |
568 | { | 608 | { |
569 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 609 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
610 | const struct soc_camera_format_xlate *xlate; | ||
611 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
612 | struct v4l2_mbus_framefmt mf; | ||
613 | int ret; | ||
570 | /* TODO: limit to mx1 hardware capabilities */ | 614 | /* TODO: limit to mx1 hardware capabilities */ |
571 | 615 | ||
616 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
617 | if (!xlate) { | ||
618 | dev_warn(icd->dev.parent, "Format %x not found\n", | ||
619 | pix->pixelformat); | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | mf.width = pix->width; | ||
624 | mf.height = pix->height; | ||
625 | mf.field = pix->field; | ||
626 | mf.colorspace = pix->colorspace; | ||
627 | mf.code = xlate->code; | ||
628 | |||
572 | /* limit to sensor capabilities */ | 629 | /* limit to sensor capabilities */ |
573 | return v4l2_subdev_call(sd, video, try_fmt, f); | 630 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); |
631 | if (ret < 0) | ||
632 | return ret; | ||
633 | |||
634 | pix->width = mf.width; | ||
635 | pix->height = mf.height; | ||
636 | pix->field = mf.field; | ||
637 | pix->colorspace = mf.colorspace; | ||
638 | |||
639 | return 0; | ||
574 | } | 640 | } |
575 | 641 | ||
576 | static int mx1_camera_reqbufs(struct soc_camera_file *icf, | 642 | static int mx1_camera_reqbufs(struct soc_camera_file *icf, |
@@ -578,10 +644,12 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf, | |||
578 | { | 644 | { |
579 | int i; | 645 | int i; |
580 | 646 | ||
581 | /* This is for locking debugging only. I removed spinlocks and now I | 647 | /* |
648 | * This is for locking debugging only. I removed spinlocks and now I | ||
582 | * check whether .prepare is ever called on a linked buffer, or whether | 649 | * check whether .prepare is ever called on a linked buffer, or whether |
583 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | 650 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now |
584 | * it hadn't triggered */ | 651 | * it hadn't triggered |
652 | */ | ||
585 | for (i = 0; i < p->count; i++) { | 653 | for (i = 0; i < p->count; i++) { |
586 | struct mx1_buffer *buf = container_of(icf->vb_vidq.bufs[i], | 654 | struct mx1_buffer *buf = container_of(icf->vb_vidq.bufs[i], |
587 | struct mx1_buffer, vb); | 655 | struct mx1_buffer, vb); |
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 7db82bdf6f31..bd297f567dc7 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <media/v4l2-dev.h> | 23 | #include <media/v4l2-dev.h> |
24 | #include <media/videobuf-dma-contig.h> | 24 | #include <media/videobuf-dma-contig.h> |
25 | #include <media/soc_camera.h> | 25 | #include <media/soc_camera.h> |
26 | #include <media/soc_mediabus.h> | ||
26 | 27 | ||
27 | #include <mach/ipu.h> | 28 | #include <mach/ipu.h> |
28 | #include <mach/mx3_camera.h> | 29 | #include <mach/mx3_camera.h> |
@@ -63,7 +64,7 @@ | |||
63 | struct mx3_camera_buffer { | 64 | struct mx3_camera_buffer { |
64 | /* common v4l buffer stuff -- must be first */ | 65 | /* common v4l buffer stuff -- must be first */ |
65 | struct videobuf_buffer vb; | 66 | struct videobuf_buffer vb; |
66 | const struct soc_camera_data_format *fmt; | 67 | enum v4l2_mbus_pixelcode code; |
67 | 68 | ||
68 | /* One descriptot per scatterlist (per frame) */ | 69 | /* One descriptot per scatterlist (per frame) */ |
69 | struct dma_async_tx_descriptor *txd; | 70 | struct dma_async_tx_descriptor *txd; |
@@ -118,8 +119,6 @@ struct dma_chan_request { | |||
118 | enum ipu_channel id; | 119 | enum ipu_channel id; |
119 | }; | 120 | }; |
120 | 121 | ||
121 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt); | ||
122 | |||
123 | static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) | 122 | static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) |
124 | { | 123 | { |
125 | return __raw_readl(mx3->base + reg); | 124 | return __raw_readl(mx3->base + reg); |
@@ -211,17 +210,16 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
211 | struct soc_camera_device *icd = vq->priv_data; | 210 | struct soc_camera_device *icd = vq->priv_data; |
212 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 211 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
213 | struct mx3_camera_dev *mx3_cam = ici->priv; | 212 | struct mx3_camera_dev *mx3_cam = ici->priv; |
214 | /* | 213 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
215 | * bits-per-pixel (depth) as specified in camera's pixel format does | 214 | icd->current_fmt->host_fmt); |
216 | * not necessarily match what the camera interface writes to RAM, but | 215 | |
217 | * it should be good enough for now. | 216 | if (bytes_per_line < 0) |
218 | */ | 217 | return bytes_per_line; |
219 | unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8); | ||
220 | 218 | ||
221 | if (!mx3_cam->idmac_channel[0]) | 219 | if (!mx3_cam->idmac_channel[0]) |
222 | return -EINVAL; | 220 | return -EINVAL; |
223 | 221 | ||
224 | *size = icd->user_width * icd->user_height * bpp; | 222 | *size = bytes_per_line * icd->user_height; |
225 | 223 | ||
226 | if (!*count) | 224 | if (!*count) |
227 | *count = 32; | 225 | *count = 32; |
@@ -241,21 +239,26 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq, | |||
241 | struct mx3_camera_dev *mx3_cam = ici->priv; | 239 | struct mx3_camera_dev *mx3_cam = ici->priv; |
242 | struct mx3_camera_buffer *buf = | 240 | struct mx3_camera_buffer *buf = |
243 | container_of(vb, struct mx3_camera_buffer, vb); | 241 | container_of(vb, struct mx3_camera_buffer, vb); |
244 | /* current_fmt _must_ always be set */ | 242 | size_t new_size; |
245 | size_t new_size = icd->user_width * icd->user_height * | ||
246 | ((icd->current_fmt->depth + 7) >> 3); | ||
247 | int ret; | 243 | int ret; |
244 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
245 | icd->current_fmt->host_fmt); | ||
246 | |||
247 | if (bytes_per_line < 0) | ||
248 | return bytes_per_line; | ||
249 | |||
250 | new_size = bytes_per_line * icd->user_height; | ||
248 | 251 | ||
249 | /* | 252 | /* |
250 | * I think, in buf_prepare you only have to protect global data, | 253 | * I think, in buf_prepare you only have to protect global data, |
251 | * the actual buffer is yours | 254 | * the actual buffer is yours |
252 | */ | 255 | */ |
253 | 256 | ||
254 | if (buf->fmt != icd->current_fmt || | 257 | if (buf->code != icd->current_fmt->code || |
255 | vb->width != icd->user_width || | 258 | vb->width != icd->user_width || |
256 | vb->height != icd->user_height || | 259 | vb->height != icd->user_height || |
257 | vb->field != field) { | 260 | vb->field != field) { |
258 | buf->fmt = icd->current_fmt; | 261 | buf->code = icd->current_fmt->code; |
259 | vb->width = icd->user_width; | 262 | vb->width = icd->user_width; |
260 | vb->height = icd->user_height; | 263 | vb->height = icd->user_height; |
261 | vb->field = field; | 264 | vb->field = field; |
@@ -348,13 +351,13 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, | |||
348 | struct dma_async_tx_descriptor *txd = buf->txd; | 351 | struct dma_async_tx_descriptor *txd = buf->txd; |
349 | struct idmac_channel *ichan = to_idmac_chan(txd->chan); | 352 | struct idmac_channel *ichan = to_idmac_chan(txd->chan); |
350 | struct idmac_video_param *video = &ichan->params.video; | 353 | struct idmac_video_param *video = &ichan->params.video; |
351 | const struct soc_camera_data_format *data_fmt = icd->current_fmt; | ||
352 | dma_cookie_t cookie; | 354 | dma_cookie_t cookie; |
355 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | ||
353 | 356 | ||
354 | BUG_ON(!irqs_disabled()); | 357 | BUG_ON(!irqs_disabled()); |
355 | 358 | ||
356 | /* This is the configuration of one sg-element */ | 359 | /* This is the configuration of one sg-element */ |
357 | video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); | 360 | video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); |
358 | video->out_width = icd->user_width; | 361 | video->out_width = icd->user_width; |
359 | video->out_height = icd->user_height; | 362 | video->out_height = icd->user_height; |
360 | video->out_stride = icd->user_width; | 363 | video->out_stride = icd->user_width; |
@@ -564,30 +567,37 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
564 | SOCAM_DATA_ACTIVE_HIGH | | 567 | SOCAM_DATA_ACTIVE_HIGH | |
565 | SOCAM_DATA_ACTIVE_LOW; | 568 | SOCAM_DATA_ACTIVE_LOW; |
566 | 569 | ||
567 | /* If requested data width is supported by the platform, use it or any | 570 | /* |
568 | * possible lower value - i.MX31 is smart enough to schift bits */ | 571 | * If requested data width is supported by the platform, use it or any |
572 | * possible lower value - i.MX31 is smart enough to schift bits | ||
573 | */ | ||
574 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
575 | *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | | ||
576 | SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
577 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
578 | *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | | ||
579 | SOCAM_DATAWIDTH_4; | ||
580 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
581 | *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
582 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
583 | *flags |= SOCAM_DATAWIDTH_4; | ||
584 | |||
569 | switch (buswidth) { | 585 | switch (buswidth) { |
570 | case 15: | 586 | case 15: |
571 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)) | 587 | if (!(*flags & SOCAM_DATAWIDTH_15)) |
572 | return -EINVAL; | 588 | return -EINVAL; |
573 | *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | | ||
574 | SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
575 | break; | 589 | break; |
576 | case 10: | 590 | case 10: |
577 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)) | 591 | if (!(*flags & SOCAM_DATAWIDTH_10)) |
578 | return -EINVAL; | 592 | return -EINVAL; |
579 | *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | | ||
580 | SOCAM_DATAWIDTH_4; | ||
581 | break; | 593 | break; |
582 | case 8: | 594 | case 8: |
583 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)) | 595 | if (!(*flags & SOCAM_DATAWIDTH_8)) |
584 | return -EINVAL; | 596 | return -EINVAL; |
585 | *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
586 | break; | 597 | break; |
587 | case 4: | 598 | case 4: |
588 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)) | 599 | if (!(*flags & SOCAM_DATAWIDTH_4)) |
589 | return -EINVAL; | 600 | return -EINVAL; |
590 | *flags |= SOCAM_DATAWIDTH_4; | ||
591 | break; | 601 | break; |
592 | default: | 602 | default: |
593 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, | 603 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, |
@@ -636,91 +646,92 @@ static bool chan_filter(struct dma_chan *chan, void *arg) | |||
636 | pdata->dma_dev == chan->device->dev; | 646 | pdata->dma_dev == chan->device->dev; |
637 | } | 647 | } |
638 | 648 | ||
639 | static const struct soc_camera_data_format mx3_camera_formats[] = { | 649 | static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { |
640 | { | 650 | { |
641 | .name = "Bayer (sRGB) 8 bit", | 651 | .fourcc = V4L2_PIX_FMT_SBGGR8, |
642 | .depth = 8, | 652 | .name = "Bayer BGGR (sRGB) 8 bit", |
643 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 653 | .bits_per_sample = 8, |
644 | .colorspace = V4L2_COLORSPACE_SRGB, | 654 | .packing = SOC_MBUS_PACKING_NONE, |
655 | .order = SOC_MBUS_ORDER_LE, | ||
645 | }, { | 656 | }, { |
646 | .name = "Monochrome 8 bit", | 657 | .fourcc = V4L2_PIX_FMT_GREY, |
647 | .depth = 8, | 658 | .name = "Monochrome 8 bit", |
648 | .fourcc = V4L2_PIX_FMT_GREY, | 659 | .bits_per_sample = 8, |
649 | .colorspace = V4L2_COLORSPACE_JPEG, | 660 | .packing = SOC_MBUS_PACKING_NONE, |
661 | .order = SOC_MBUS_ORDER_LE, | ||
650 | }, | 662 | }, |
651 | }; | 663 | }; |
652 | 664 | ||
653 | static bool buswidth_supported(struct soc_camera_host *ici, int depth) | 665 | /* This will be corrected as we get more formats */ |
666 | static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
654 | { | 667 | { |
655 | struct mx3_camera_dev *mx3_cam = ici->priv; | 668 | return fmt->packing == SOC_MBUS_PACKING_NONE || |
656 | 669 | (fmt->bits_per_sample == 8 && | |
657 | switch (depth) { | 670 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || |
658 | case 4: | 671 | (fmt->bits_per_sample > 8 && |
659 | return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4); | 672 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
660 | case 8: | ||
661 | return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8); | ||
662 | case 10: | ||
663 | return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10); | ||
664 | case 15: | ||
665 | return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15); | ||
666 | } | ||
667 | return false; | ||
668 | } | 673 | } |
669 | 674 | ||
670 | static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, | 675 | static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, |
671 | struct soc_camera_format_xlate *xlate) | 676 | struct soc_camera_format_xlate *xlate) |
672 | { | 677 | { |
673 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 678 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
674 | int formats = 0, buswidth, ret; | 679 | struct device *dev = icd->dev.parent; |
680 | int formats = 0, ret; | ||
681 | enum v4l2_mbus_pixelcode code; | ||
682 | const struct soc_mbus_pixelfmt *fmt; | ||
675 | 683 | ||
676 | buswidth = icd->formats[idx].depth; | 684 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); |
685 | if (ret < 0) | ||
686 | /* No more formats */ | ||
687 | return 0; | ||
677 | 688 | ||
678 | if (!buswidth_supported(ici, buswidth)) | 689 | fmt = soc_mbus_get_fmtdesc(code); |
690 | if (!fmt) { | ||
691 | dev_err(icd->dev.parent, | ||
692 | "Invalid format code #%d: %d\n", idx, code); | ||
679 | return 0; | 693 | return 0; |
694 | } | ||
680 | 695 | ||
681 | ret = mx3_camera_try_bus_param(icd, buswidth); | 696 | /* This also checks support for the requested bits-per-sample */ |
697 | ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
682 | if (ret < 0) | 698 | if (ret < 0) |
683 | return 0; | 699 | return 0; |
684 | 700 | ||
685 | switch (icd->formats[idx].fourcc) { | 701 | switch (code) { |
686 | case V4L2_PIX_FMT_SGRBG10: | 702 | case V4L2_MBUS_FMT_SBGGR10_1X10: |
687 | formats++; | 703 | formats++; |
688 | if (xlate) { | 704 | if (xlate) { |
689 | xlate->host_fmt = &mx3_camera_formats[0]; | 705 | xlate->host_fmt = &mx3_camera_formats[0]; |
690 | xlate->cam_fmt = icd->formats + idx; | 706 | xlate->code = code; |
691 | xlate->buswidth = buswidth; | ||
692 | xlate++; | 707 | xlate++; |
693 | dev_dbg(icd->dev.parent, | 708 | dev_dbg(dev, "Providing format %s using code %d\n", |
694 | "Providing format %s using %s\n", | 709 | mx3_camera_formats[0].name, code); |
695 | mx3_camera_formats[0].name, | ||
696 | icd->formats[idx].name); | ||
697 | } | 710 | } |
698 | goto passthrough; | 711 | break; |
699 | case V4L2_PIX_FMT_Y16: | 712 | case V4L2_MBUS_FMT_Y10_1X10: |
700 | formats++; | 713 | formats++; |
701 | if (xlate) { | 714 | if (xlate) { |
702 | xlate->host_fmt = &mx3_camera_formats[1]; | 715 | xlate->host_fmt = &mx3_camera_formats[1]; |
703 | xlate->cam_fmt = icd->formats + idx; | 716 | xlate->code = code; |
704 | xlate->buswidth = buswidth; | ||
705 | xlate++; | 717 | xlate++; |
706 | dev_dbg(icd->dev.parent, | 718 | dev_dbg(dev, "Providing format %s using code %d\n", |
707 | "Providing format %s using %s\n", | 719 | mx3_camera_formats[1].name, code); |
708 | mx3_camera_formats[0].name, | ||
709 | icd->formats[idx].name); | ||
710 | } | 720 | } |
721 | break; | ||
711 | default: | 722 | default: |
712 | passthrough: | 723 | if (!mx3_camera_packing_supported(fmt)) |
713 | /* Generic pass-through */ | 724 | return 0; |
714 | formats++; | 725 | } |
715 | if (xlate) { | 726 | |
716 | xlate->host_fmt = icd->formats + idx; | 727 | /* Generic pass-through */ |
717 | xlate->cam_fmt = icd->formats + idx; | 728 | formats++; |
718 | xlate->buswidth = buswidth; | 729 | if (xlate) { |
719 | xlate++; | 730 | xlate->host_fmt = fmt; |
720 | dev_dbg(icd->dev.parent, | 731 | xlate->code = code; |
721 | "Providing format %s in pass-through mode\n", | 732 | xlate++; |
722 | icd->formats[idx].name); | 733 | dev_dbg(dev, "Providing format %x in pass-through mode\n", |
723 | } | 734 | xlate->host_fmt->fourcc); |
724 | } | 735 | } |
725 | 736 | ||
726 | return formats; | 737 | return formats; |
@@ -804,8 +815,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, | |||
804 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 815 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
805 | struct mx3_camera_dev *mx3_cam = ici->priv; | 816 | struct mx3_camera_dev *mx3_cam = ici->priv; |
806 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 817 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
807 | struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; | 818 | struct v4l2_mbus_framefmt mf; |
808 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
809 | int ret; | 819 | int ret; |
810 | 820 | ||
811 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); | 821 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); |
@@ -816,19 +826,19 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, | |||
816 | return ret; | 826 | return ret; |
817 | 827 | ||
818 | /* The capture device might have changed its output */ | 828 | /* The capture device might have changed its output */ |
819 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | 829 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
820 | if (ret < 0) | 830 | if (ret < 0) |
821 | return ret; | 831 | return ret; |
822 | 832 | ||
823 | if (pix->width & 7) { | 833 | if (mf.width & 7) { |
824 | /* Ouch! We can only handle 8-byte aligned width... */ | 834 | /* Ouch! We can only handle 8-byte aligned width... */ |
825 | stride_align(&pix->width); | 835 | stride_align(&mf.width); |
826 | ret = v4l2_subdev_call(sd, video, s_fmt, &f); | 836 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); |
827 | if (ret < 0) | 837 | if (ret < 0) |
828 | return ret; | 838 | return ret; |
829 | } | 839 | } |
830 | 840 | ||
831 | if (pix->width != icd->user_width || pix->height != icd->user_height) { | 841 | if (mf.width != icd->user_width || mf.height != icd->user_height) { |
832 | /* | 842 | /* |
833 | * We now know pixel formats and can decide upon DMA-channel(s) | 843 | * We now know pixel formats and can decide upon DMA-channel(s) |
834 | * So far only direct camera-to-memory is supported | 844 | * So far only direct camera-to-memory is supported |
@@ -839,14 +849,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, | |||
839 | return ret; | 849 | return ret; |
840 | } | 850 | } |
841 | 851 | ||
842 | configure_geometry(mx3_cam, pix->width, pix->height); | 852 | configure_geometry(mx3_cam, mf.width, mf.height); |
843 | } | 853 | } |
844 | 854 | ||
845 | dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", | 855 | dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", |
846 | pix->width, pix->height); | 856 | mf.width, mf.height); |
847 | 857 | ||
848 | icd->user_width = pix->width; | 858 | icd->user_width = mf.width; |
849 | icd->user_height = pix->height; | 859 | icd->user_height = mf.height; |
850 | 860 | ||
851 | return ret; | 861 | return ret; |
852 | } | 862 | } |
@@ -859,6 +869,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
859 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 869 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
860 | const struct soc_camera_format_xlate *xlate; | 870 | const struct soc_camera_format_xlate *xlate; |
861 | struct v4l2_pix_format *pix = &f->fmt.pix; | 871 | struct v4l2_pix_format *pix = &f->fmt.pix; |
872 | struct v4l2_mbus_framefmt mf; | ||
862 | int ret; | 873 | int ret; |
863 | 874 | ||
864 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 875 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
@@ -883,11 +894,24 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
883 | 894 | ||
884 | configure_geometry(mx3_cam, pix->width, pix->height); | 895 | configure_geometry(mx3_cam, pix->width, pix->height); |
885 | 896 | ||
886 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 897 | mf.width = pix->width; |
887 | if (!ret) { | 898 | mf.height = pix->height; |
888 | icd->buswidth = xlate->buswidth; | 899 | mf.field = pix->field; |
889 | icd->current_fmt = xlate->host_fmt; | 900 | mf.colorspace = pix->colorspace; |
890 | } | 901 | mf.code = xlate->code; |
902 | |||
903 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
904 | if (ret < 0) | ||
905 | return ret; | ||
906 | |||
907 | if (mf.code != xlate->code) | ||
908 | return -EINVAL; | ||
909 | |||
910 | pix->width = mf.width; | ||
911 | pix->height = mf.height; | ||
912 | pix->field = mf.field; | ||
913 | pix->colorspace = mf.colorspace; | ||
914 | icd->current_fmt = xlate; | ||
891 | 915 | ||
892 | dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); | 916 | dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); |
893 | 917 | ||
@@ -900,8 +924,8 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, | |||
900 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 924 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
901 | const struct soc_camera_format_xlate *xlate; | 925 | const struct soc_camera_format_xlate *xlate; |
902 | struct v4l2_pix_format *pix = &f->fmt.pix; | 926 | struct v4l2_pix_format *pix = &f->fmt.pix; |
927 | struct v4l2_mbus_framefmt mf; | ||
903 | __u32 pixfmt = pix->pixelformat; | 928 | __u32 pixfmt = pix->pixelformat; |
904 | enum v4l2_field field; | ||
905 | int ret; | 929 | int ret; |
906 | 930 | ||
907 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 931 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
@@ -916,23 +940,37 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, | |||
916 | if (pix->width > 4096) | 940 | if (pix->width > 4096) |
917 | pix->width = 4096; | 941 | pix->width = 4096; |
918 | 942 | ||
919 | pix->bytesperline = pix->width * | 943 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, |
920 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 944 | xlate->host_fmt); |
945 | if (pix->bytesperline < 0) | ||
946 | return pix->bytesperline; | ||
921 | pix->sizeimage = pix->height * pix->bytesperline; | 947 | pix->sizeimage = pix->height * pix->bytesperline; |
922 | 948 | ||
923 | /* camera has to see its format, but the user the original one */ | ||
924 | pix->pixelformat = xlate->cam_fmt->fourcc; | ||
925 | /* limit to sensor capabilities */ | 949 | /* limit to sensor capabilities */ |
926 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 950 | mf.width = pix->width; |
927 | pix->pixelformat = xlate->host_fmt->fourcc; | 951 | mf.height = pix->height; |
952 | mf.field = pix->field; | ||
953 | mf.colorspace = pix->colorspace; | ||
954 | mf.code = xlate->code; | ||
955 | |||
956 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
957 | if (ret < 0) | ||
958 | return ret; | ||
928 | 959 | ||
929 | field = pix->field; | 960 | pix->width = mf.width; |
961 | pix->height = mf.height; | ||
962 | pix->colorspace = mf.colorspace; | ||
930 | 963 | ||
931 | if (field == V4L2_FIELD_ANY) { | 964 | switch (mf.field) { |
965 | case V4L2_FIELD_ANY: | ||
932 | pix->field = V4L2_FIELD_NONE; | 966 | pix->field = V4L2_FIELD_NONE; |
933 | } else if (field != V4L2_FIELD_NONE) { | 967 | break; |
934 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); | 968 | case V4L2_FIELD_NONE: |
935 | return -EINVAL; | 969 | break; |
970 | default: | ||
971 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", | ||
972 | mf.field); | ||
973 | ret = -EINVAL; | ||
936 | } | 974 | } |
937 | 975 | ||
938 | return ret; | 976 | return ret; |
@@ -968,18 +1006,26 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
968 | struct mx3_camera_dev *mx3_cam = ici->priv; | 1006 | struct mx3_camera_dev *mx3_cam = ici->priv; |
969 | unsigned long bus_flags, camera_flags, common_flags; | 1007 | unsigned long bus_flags, camera_flags, common_flags; |
970 | u32 dw, sens_conf; | 1008 | u32 dw, sens_conf; |
971 | int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags); | 1009 | const struct soc_mbus_pixelfmt *fmt; |
1010 | int buswidth; | ||
1011 | int ret; | ||
972 | const struct soc_camera_format_xlate *xlate; | 1012 | const struct soc_camera_format_xlate *xlate; |
973 | struct device *dev = icd->dev.parent; | 1013 | struct device *dev = icd->dev.parent; |
974 | 1014 | ||
1015 | fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); | ||
1016 | if (!fmt) | ||
1017 | return -EINVAL; | ||
1018 | |||
1019 | buswidth = fmt->bits_per_sample; | ||
1020 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
1021 | |||
975 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1022 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
976 | if (!xlate) { | 1023 | if (!xlate) { |
977 | dev_warn(dev, "Format %x not found\n", pixfmt); | 1024 | dev_warn(dev, "Format %x not found\n", pixfmt); |
978 | return -EINVAL; | 1025 | return -EINVAL; |
979 | } | 1026 | } |
980 | 1027 | ||
981 | dev_dbg(dev, "requested bus width %d bit: %d\n", | 1028 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); |
982 | icd->buswidth, ret); | ||
983 | 1029 | ||
984 | if (ret < 0) | 1030 | if (ret < 0) |
985 | return ret; | 1031 | return ret; |
@@ -1027,8 +1073,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1027 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1073 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; |
1028 | } | 1074 | } |
1029 | 1075 | ||
1030 | /* Make the camera work in widest common mode, we'll take care of | 1076 | /* |
1031 | * the rest */ | 1077 | * Make the camera work in widest common mode, we'll take care of |
1078 | * the rest | ||
1079 | */ | ||
1032 | if (common_flags & SOCAM_DATAWIDTH_15) | 1080 | if (common_flags & SOCAM_DATAWIDTH_15) |
1033 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | 1081 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | |
1034 | SOCAM_DATAWIDTH_15; | 1082 | SOCAM_DATAWIDTH_15; |
@@ -1078,7 +1126,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1078 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | 1126 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; |
1079 | 1127 | ||
1080 | /* Just do what we're asked to do */ | 1128 | /* Just do what we're asked to do */ |
1081 | switch (xlate->host_fmt->depth) { | 1129 | switch (xlate->host_fmt->bits_per_sample) { |
1082 | case 4: | 1130 | case 4: |
1083 | dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | 1131 | dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; |
1084 | break; | 1132 | break; |
@@ -1152,8 +1200,10 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
1152 | if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | | 1200 | if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | |
1153 | MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | | 1201 | MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | |
1154 | MX3_CAMERA_DATAWIDTH_15))) { | 1202 | MX3_CAMERA_DATAWIDTH_15))) { |
1155 | /* Platform hasn't set available data widths. This is bad. | 1203 | /* |
1156 | * Warn and use a default. */ | 1204 | * Platform hasn't set available data widths. This is bad. |
1205 | * Warn and use a default. | ||
1206 | */ | ||
1157 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | 1207 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " |
1158 | "data widths, using default 8 bit\n"); | 1208 | "data widths, using default 8 bit\n"); |
1159 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | 1209 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; |
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 5fc4ac0d88f0..7400eacb4d64 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c | |||
@@ -1450,12 +1450,11 @@ static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma) | |||
1450 | 1450 | ||
1451 | static int omap24xxcam_open(struct file *file) | 1451 | static int omap24xxcam_open(struct file *file) |
1452 | { | 1452 | { |
1453 | int minor = video_devdata(file)->minor; | ||
1454 | struct omap24xxcam_device *cam = omap24xxcam.priv; | 1453 | struct omap24xxcam_device *cam = omap24xxcam.priv; |
1455 | struct omap24xxcam_fh *fh; | 1454 | struct omap24xxcam_fh *fh; |
1456 | struct v4l2_format format; | 1455 | struct v4l2_format format; |
1457 | 1456 | ||
1458 | if (!cam || !cam->vfd || (cam->vfd->minor != minor)) | 1457 | if (!cam || !cam->vfd) |
1459 | return -ENODEV; | 1458 | return -ENODEV; |
1460 | 1459 | ||
1461 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 1460 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
@@ -1660,7 +1659,6 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s) | |||
1660 | 1659 | ||
1661 | strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); | 1660 | strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); |
1662 | vfd->fops = &omap24xxcam_fops; | 1661 | vfd->fops = &omap24xxcam_fops; |
1663 | vfd->minor = -1; | ||
1664 | vfd->ioctl_ops = &omap24xxcam_ioctl_fops; | 1662 | vfd->ioctl_ops = &omap24xxcam_ioctl_fops; |
1665 | 1663 | ||
1666 | omap24xxcam_hwinit(cam); | 1664 | omap24xxcam_hwinit(cam); |
@@ -1671,14 +1669,14 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s) | |||
1671 | 1669 | ||
1672 | if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { | 1670 | if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { |
1673 | dev_err(cam->dev, "could not register V4L device\n"); | 1671 | dev_err(cam->dev, "could not register V4L device\n"); |
1674 | vfd->minor = -1; | ||
1675 | rval = -EBUSY; | 1672 | rval = -EBUSY; |
1676 | goto err; | 1673 | goto err; |
1677 | } | 1674 | } |
1678 | 1675 | ||
1679 | omap24xxcam_poweron_reset(cam); | 1676 | omap24xxcam_poweron_reset(cam); |
1680 | 1677 | ||
1681 | dev_info(cam->dev, "registered device video%d\n", vfd->minor); | 1678 | dev_info(cam->dev, "registered device %s\n", |
1679 | video_device_node_name(vfd)); | ||
1682 | 1680 | ||
1683 | return 0; | 1681 | return 0; |
1684 | 1682 | ||
@@ -1695,7 +1693,7 @@ static void omap24xxcam_device_unregister(struct v4l2_int_device *s) | |||
1695 | omap24xxcam_sensor_exit(cam); | 1693 | omap24xxcam_sensor_exit(cam); |
1696 | 1694 | ||
1697 | if (cam->vfd) { | 1695 | if (cam->vfd) { |
1698 | if (cam->vfd->minor == -1) { | 1696 | if (!video_is_registered(cam->vfd)) { |
1699 | /* | 1697 | /* |
1700 | * The device was never registered, so release the | 1698 | * The device was never registered, so release the |
1701 | * video_device struct directly. | 1699 | * video_device struct directly. |
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 0bc2cf573c76..e0bce8dc74bf 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c | |||
@@ -4674,7 +4674,6 @@ static struct video_device vdev_template = { | |||
4674 | .name = "OV511 USB Camera", | 4674 | .name = "OV511 USB Camera", |
4675 | .fops = &ov511_fops, | 4675 | .fops = &ov511_fops, |
4676 | .release = video_device_release, | 4676 | .release = video_device_release, |
4677 | .minor = -1, | ||
4678 | }; | 4677 | }; |
4679 | 4678 | ||
4680 | /**************************************************************************** | 4679 | /**************************************************************************** |
@@ -5867,8 +5866,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
5867 | ov511_devused |= 1 << nr; | 5866 | ov511_devused |= 1 << nr; |
5868 | ov->nr = nr; | 5867 | ov->nr = nr; |
5869 | 5868 | ||
5870 | dev_info(&intf->dev, "Device at %s registered to minor %d\n", | 5869 | dev_info(&intf->dev, "Device at %s registered to %s\n", |
5871 | ov->usb_path, ov->vdev->minor); | 5870 | ov->usb_path, video_device_node_name(ov->vdev)); |
5872 | 5871 | ||
5873 | usb_set_intfdata(intf, ov); | 5872 | usb_set_intfdata(intf, ov); |
5874 | if (ov_create_sysfs(ov->vdev)) { | 5873 | if (ov_create_sysfs(ov->vdev)) { |
@@ -5878,13 +5877,13 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
5878 | goto error; | 5877 | goto error; |
5879 | } | 5878 | } |
5880 | 5879 | ||
5881 | mutex_lock(&ov->lock); | 5880 | mutex_unlock(&ov->lock); |
5882 | 5881 | ||
5883 | return 0; | 5882 | return 0; |
5884 | 5883 | ||
5885 | error: | 5884 | error: |
5886 | if (ov->vdev) { | 5885 | if (ov->vdev) { |
5887 | if (-1 == ov->vdev->minor) | 5886 | if (!video_is_registered(ov->vdev)) |
5888 | video_device_release(ov->vdev); | 5887 | video_device_release(ov->vdev); |
5889 | else | 5888 | else |
5890 | video_unregister_device(ov->vdev); | 5889 | video_unregister_device(ov->vdev); |
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 205229333466..3a45e945a528 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <media/v4l2-chip-ident.h> | 24 | #include <media/v4l2-chip-ident.h> |
25 | #include <media/v4l2-subdev.h> | 25 | #include <media/v4l2-subdev.h> |
26 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
27 | #include <media/soc_mediabus.h> | ||
27 | #include <media/ov772x.h> | 28 | #include <media/ov772x.h> |
28 | 29 | ||
29 | /* | 30 | /* |
@@ -382,7 +383,8 @@ struct regval_list { | |||
382 | }; | 383 | }; |
383 | 384 | ||
384 | struct ov772x_color_format { | 385 | struct ov772x_color_format { |
385 | const struct soc_camera_data_format *format; | 386 | enum v4l2_mbus_pixelcode code; |
387 | enum v4l2_colorspace colorspace; | ||
386 | u8 dsp3; | 388 | u8 dsp3; |
387 | u8 com3; | 389 | u8 com3; |
388 | u8 com7; | 390 | u8 com7; |
@@ -399,7 +401,7 @@ struct ov772x_win_size { | |||
399 | struct ov772x_priv { | 401 | struct ov772x_priv { |
400 | struct v4l2_subdev subdev; | 402 | struct v4l2_subdev subdev; |
401 | struct ov772x_camera_info *info; | 403 | struct ov772x_camera_info *info; |
402 | const struct ov772x_color_format *fmt; | 404 | const struct ov772x_color_format *cfmt; |
403 | const struct ov772x_win_size *win; | 405 | const struct ov772x_win_size *win; |
404 | int model; | 406 | int model; |
405 | unsigned short flag_vflip:1; | 407 | unsigned short flag_vflip:1; |
@@ -434,93 +436,57 @@ static const struct regval_list ov772x_vga_regs[] = { | |||
434 | }; | 436 | }; |
435 | 437 | ||
436 | /* | 438 | /* |
437 | * supported format list | 439 | * supported color format list |
438 | */ | ||
439 | |||
440 | #define SETFOURCC(type) .name = (#type), .fourcc = (V4L2_PIX_FMT_ ## type) | ||
441 | static const struct soc_camera_data_format ov772x_fmt_lists[] = { | ||
442 | { | ||
443 | SETFOURCC(YUYV), | ||
444 | .depth = 16, | ||
445 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
446 | }, | ||
447 | { | ||
448 | SETFOURCC(YVYU), | ||
449 | .depth = 16, | ||
450 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
451 | }, | ||
452 | { | ||
453 | SETFOURCC(UYVY), | ||
454 | .depth = 16, | ||
455 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
456 | }, | ||
457 | { | ||
458 | SETFOURCC(RGB555), | ||
459 | .depth = 16, | ||
460 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
461 | }, | ||
462 | { | ||
463 | SETFOURCC(RGB555X), | ||
464 | .depth = 16, | ||
465 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
466 | }, | ||
467 | { | ||
468 | SETFOURCC(RGB565), | ||
469 | .depth = 16, | ||
470 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
471 | }, | ||
472 | { | ||
473 | SETFOURCC(RGB565X), | ||
474 | .depth = 16, | ||
475 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
476 | }, | ||
477 | }; | ||
478 | |||
479 | /* | ||
480 | * color format list | ||
481 | */ | 440 | */ |
482 | static const struct ov772x_color_format ov772x_cfmts[] = { | 441 | static const struct ov772x_color_format ov772x_cfmts[] = { |
483 | { | 442 | { |
484 | .format = &ov772x_fmt_lists[0], | 443 | .code = V4L2_MBUS_FMT_YUYV8_2X8_LE, |
485 | .dsp3 = 0x0, | 444 | .colorspace = V4L2_COLORSPACE_JPEG, |
486 | .com3 = SWAP_YUV, | 445 | .dsp3 = 0x0, |
487 | .com7 = OFMT_YUV, | 446 | .com3 = SWAP_YUV, |
447 | .com7 = OFMT_YUV, | ||
488 | }, | 448 | }, |
489 | { | 449 | { |
490 | .format = &ov772x_fmt_lists[1], | 450 | .code = V4L2_MBUS_FMT_YVYU8_2X8_LE, |
491 | .dsp3 = UV_ON, | 451 | .colorspace = V4L2_COLORSPACE_JPEG, |
492 | .com3 = SWAP_YUV, | 452 | .dsp3 = UV_ON, |
493 | .com7 = OFMT_YUV, | 453 | .com3 = SWAP_YUV, |
454 | .com7 = OFMT_YUV, | ||
494 | }, | 455 | }, |
495 | { | 456 | { |
496 | .format = &ov772x_fmt_lists[2], | 457 | .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, |
497 | .dsp3 = 0x0, | 458 | .colorspace = V4L2_COLORSPACE_JPEG, |
498 | .com3 = 0x0, | 459 | .dsp3 = 0x0, |
499 | .com7 = OFMT_YUV, | 460 | .com3 = 0x0, |
461 | .com7 = OFMT_YUV, | ||
500 | }, | 462 | }, |
501 | { | 463 | { |
502 | .format = &ov772x_fmt_lists[3], | 464 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, |
503 | .dsp3 = 0x0, | 465 | .colorspace = V4L2_COLORSPACE_SRGB, |
504 | .com3 = SWAP_RGB, | 466 | .dsp3 = 0x0, |
505 | .com7 = FMT_RGB555 | OFMT_RGB, | 467 | .com3 = SWAP_RGB, |
468 | .com7 = FMT_RGB555 | OFMT_RGB, | ||
506 | }, | 469 | }, |
507 | { | 470 | { |
508 | .format = &ov772x_fmt_lists[4], | 471 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, |
509 | .dsp3 = 0x0, | 472 | .colorspace = V4L2_COLORSPACE_SRGB, |
510 | .com3 = 0x0, | 473 | .dsp3 = 0x0, |
511 | .com7 = FMT_RGB555 | OFMT_RGB, | 474 | .com3 = 0x0, |
475 | .com7 = FMT_RGB555 | OFMT_RGB, | ||
512 | }, | 476 | }, |
513 | { | 477 | { |
514 | .format = &ov772x_fmt_lists[5], | 478 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, |
515 | .dsp3 = 0x0, | 479 | .colorspace = V4L2_COLORSPACE_SRGB, |
516 | .com3 = SWAP_RGB, | 480 | .dsp3 = 0x0, |
517 | .com7 = FMT_RGB565 | OFMT_RGB, | 481 | .com3 = SWAP_RGB, |
482 | .com7 = FMT_RGB565 | OFMT_RGB, | ||
518 | }, | 483 | }, |
519 | { | 484 | { |
520 | .format = &ov772x_fmt_lists[6], | 485 | .code = V4L2_MBUS_FMT_RGB565_2X8_BE, |
521 | .dsp3 = 0x0, | 486 | .colorspace = V4L2_COLORSPACE_SRGB, |
522 | .com3 = 0x0, | 487 | .dsp3 = 0x0, |
523 | .com7 = FMT_RGB565 | OFMT_RGB, | 488 | .com3 = 0x0, |
489 | .com7 = FMT_RGB565 | OFMT_RGB, | ||
524 | }, | 490 | }, |
525 | }; | 491 | }; |
526 | 492 | ||
@@ -642,15 +608,15 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) | |||
642 | return 0; | 608 | return 0; |
643 | } | 609 | } |
644 | 610 | ||
645 | if (!priv->win || !priv->fmt) { | 611 | if (!priv->win || !priv->cfmt) { |
646 | dev_err(&client->dev, "norm or win select error\n"); | 612 | dev_err(&client->dev, "norm or win select error\n"); |
647 | return -EPERM; | 613 | return -EPERM; |
648 | } | 614 | } |
649 | 615 | ||
650 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); | 616 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); |
651 | 617 | ||
652 | dev_dbg(&client->dev, "format %s, win %s\n", | 618 | dev_dbg(&client->dev, "format %d, win %s\n", |
653 | priv->fmt->format->name, priv->win->name); | 619 | priv->cfmt->code, priv->win->name); |
654 | 620 | ||
655 | return 0; | 621 | return 0; |
656 | } | 622 | } |
@@ -806,8 +772,8 @@ static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) | |||
806 | return win; | 772 | return win; |
807 | } | 773 | } |
808 | 774 | ||
809 | static int ov772x_set_params(struct i2c_client *client, | 775 | static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, |
810 | u32 *width, u32 *height, u32 pixfmt) | 776 | enum v4l2_mbus_pixelcode code) |
811 | { | 777 | { |
812 | struct ov772x_priv *priv = to_ov772x(client); | 778 | struct ov772x_priv *priv = to_ov772x(client); |
813 | int ret = -EINVAL; | 779 | int ret = -EINVAL; |
@@ -817,14 +783,14 @@ static int ov772x_set_params(struct i2c_client *client, | |||
817 | /* | 783 | /* |
818 | * select format | 784 | * select format |
819 | */ | 785 | */ |
820 | priv->fmt = NULL; | 786 | priv->cfmt = NULL; |
821 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { | 787 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { |
822 | if (pixfmt == ov772x_cfmts[i].format->fourcc) { | 788 | if (code == ov772x_cfmts[i].code) { |
823 | priv->fmt = ov772x_cfmts + i; | 789 | priv->cfmt = ov772x_cfmts + i; |
824 | break; | 790 | break; |
825 | } | 791 | } |
826 | } | 792 | } |
827 | if (!priv->fmt) | 793 | if (!priv->cfmt) |
828 | goto ov772x_set_fmt_error; | 794 | goto ov772x_set_fmt_error; |
829 | 795 | ||
830 | /* | 796 | /* |
@@ -894,7 +860,7 @@ static int ov772x_set_params(struct i2c_client *client, | |||
894 | /* | 860 | /* |
895 | * set DSP_CTRL3 | 861 | * set DSP_CTRL3 |
896 | */ | 862 | */ |
897 | val = priv->fmt->dsp3; | 863 | val = priv->cfmt->dsp3; |
898 | if (val) { | 864 | if (val) { |
899 | ret = ov772x_mask_set(client, | 865 | ret = ov772x_mask_set(client, |
900 | DSP_CTRL3, UV_MASK, val); | 866 | DSP_CTRL3, UV_MASK, val); |
@@ -905,7 +871,7 @@ static int ov772x_set_params(struct i2c_client *client, | |||
905 | /* | 871 | /* |
906 | * set COM3 | 872 | * set COM3 |
907 | */ | 873 | */ |
908 | val = priv->fmt->com3; | 874 | val = priv->cfmt->com3; |
909 | if (priv->info->flags & OV772X_FLAG_VFLIP) | 875 | if (priv->info->flags & OV772X_FLAG_VFLIP) |
910 | val |= VFLIP_IMG; | 876 | val |= VFLIP_IMG; |
911 | if (priv->info->flags & OV772X_FLAG_HFLIP) | 877 | if (priv->info->flags & OV772X_FLAG_HFLIP) |
@@ -923,9 +889,9 @@ static int ov772x_set_params(struct i2c_client *client, | |||
923 | /* | 889 | /* |
924 | * set COM7 | 890 | * set COM7 |
925 | */ | 891 | */ |
926 | val = priv->win->com7_bit | priv->fmt->com7; | 892 | val = priv->win->com7_bit | priv->cfmt->com7; |
927 | ret = ov772x_mask_set(client, | 893 | ret = ov772x_mask_set(client, |
928 | COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), | 894 | COM7, SLCT_MASK | FMT_MASK | OFMT_MASK, |
929 | val); | 895 | val); |
930 | if (ret < 0) | 896 | if (ret < 0) |
931 | goto ov772x_set_fmt_error; | 897 | goto ov772x_set_fmt_error; |
@@ -951,7 +917,7 @@ ov772x_set_fmt_error: | |||
951 | 917 | ||
952 | ov772x_reset(client); | 918 | ov772x_reset(client); |
953 | priv->win = NULL; | 919 | priv->win = NULL; |
954 | priv->fmt = NULL; | 920 | priv->cfmt = NULL; |
955 | 921 | ||
956 | return ret; | 922 | return ret; |
957 | } | 923 | } |
@@ -981,54 +947,79 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
981 | return 0; | 947 | return 0; |
982 | } | 948 | } |
983 | 949 | ||
984 | static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 950 | static int ov772x_g_fmt(struct v4l2_subdev *sd, |
951 | struct v4l2_mbus_framefmt *mf) | ||
985 | { | 952 | { |
986 | struct i2c_client *client = sd->priv; | 953 | struct i2c_client *client = sd->priv; |
987 | struct ov772x_priv *priv = to_ov772x(client); | 954 | struct ov772x_priv *priv = to_ov772x(client); |
988 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
989 | 955 | ||
990 | if (!priv->win || !priv->fmt) { | 956 | if (!priv->win || !priv->cfmt) { |
991 | u32 width = VGA_WIDTH, height = VGA_HEIGHT; | 957 | u32 width = VGA_WIDTH, height = VGA_HEIGHT; |
992 | int ret = ov772x_set_params(client, &width, &height, | 958 | int ret = ov772x_set_params(client, &width, &height, |
993 | V4L2_PIX_FMT_YUYV); | 959 | V4L2_MBUS_FMT_YUYV8_2X8_LE); |
994 | if (ret < 0) | 960 | if (ret < 0) |
995 | return ret; | 961 | return ret; |
996 | } | 962 | } |
997 | 963 | ||
998 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 964 | mf->width = priv->win->width; |
999 | 965 | mf->height = priv->win->height; | |
1000 | pix->width = priv->win->width; | 966 | mf->code = priv->cfmt->code; |
1001 | pix->height = priv->win->height; | 967 | mf->colorspace = priv->cfmt->colorspace; |
1002 | pix->pixelformat = priv->fmt->format->fourcc; | 968 | mf->field = V4L2_FIELD_NONE; |
1003 | pix->colorspace = priv->fmt->format->colorspace; | ||
1004 | pix->field = V4L2_FIELD_NONE; | ||
1005 | 969 | ||
1006 | return 0; | 970 | return 0; |
1007 | } | 971 | } |
1008 | 972 | ||
1009 | static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 973 | static int ov772x_s_fmt(struct v4l2_subdev *sd, |
974 | struct v4l2_mbus_framefmt *mf) | ||
1010 | { | 975 | { |
1011 | struct i2c_client *client = sd->priv; | 976 | struct i2c_client *client = sd->priv; |
1012 | struct v4l2_pix_format *pix = &f->fmt.pix; | 977 | struct ov772x_priv *priv = to_ov772x(client); |
978 | int ret = ov772x_set_params(client, &mf->width, &mf->height, | ||
979 | mf->code); | ||
980 | |||
981 | if (!ret) | ||
982 | mf->colorspace = priv->cfmt->colorspace; | ||
1013 | 983 | ||
1014 | return ov772x_set_params(client, &pix->width, &pix->height, | 984 | return ret; |
1015 | pix->pixelformat); | ||
1016 | } | 985 | } |
1017 | 986 | ||
1018 | static int ov772x_try_fmt(struct v4l2_subdev *sd, | 987 | static int ov772x_try_fmt(struct v4l2_subdev *sd, |
1019 | struct v4l2_format *f) | 988 | struct v4l2_mbus_framefmt *mf) |
1020 | { | 989 | { |
1021 | struct v4l2_pix_format *pix = &f->fmt.pix; | 990 | struct i2c_client *client = sd->priv; |
991 | struct ov772x_priv *priv = to_ov772x(client); | ||
1022 | const struct ov772x_win_size *win; | 992 | const struct ov772x_win_size *win; |
993 | int i; | ||
1023 | 994 | ||
1024 | /* | 995 | /* |
1025 | * select suitable win | 996 | * select suitable win |
1026 | */ | 997 | */ |
1027 | win = ov772x_select_win(pix->width, pix->height); | 998 | win = ov772x_select_win(mf->width, mf->height); |
999 | |||
1000 | mf->width = win->width; | ||
1001 | mf->height = win->height; | ||
1002 | mf->field = V4L2_FIELD_NONE; | ||
1028 | 1003 | ||
1029 | pix->width = win->width; | 1004 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) |
1030 | pix->height = win->height; | 1005 | if (mf->code == ov772x_cfmts[i].code) |
1031 | pix->field = V4L2_FIELD_NONE; | 1006 | break; |
1007 | |||
1008 | if (i == ARRAY_SIZE(ov772x_cfmts)) { | ||
1009 | /* Unsupported format requested. Propose either */ | ||
1010 | if (priv->cfmt) { | ||
1011 | /* the current one or */ | ||
1012 | mf->colorspace = priv->cfmt->colorspace; | ||
1013 | mf->code = priv->cfmt->code; | ||
1014 | } else { | ||
1015 | /* the default one */ | ||
1016 | mf->colorspace = ov772x_cfmts[0].colorspace; | ||
1017 | mf->code = ov772x_cfmts[0].code; | ||
1018 | } | ||
1019 | } else { | ||
1020 | /* Also return the colorspace */ | ||
1021 | mf->colorspace = ov772x_cfmts[i].colorspace; | ||
1022 | } | ||
1032 | 1023 | ||
1033 | return 0; | 1024 | return 0; |
1034 | } | 1025 | } |
@@ -1057,9 +1048,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd, | |||
1057 | return -ENODEV; | 1048 | return -ENODEV; |
1058 | } | 1049 | } |
1059 | 1050 | ||
1060 | icd->formats = ov772x_fmt_lists; | ||
1061 | icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists); | ||
1062 | |||
1063 | /* | 1051 | /* |
1064 | * check and show product ID and manufacturer ID | 1052 | * check and show product ID and manufacturer ID |
1065 | */ | 1053 | */ |
@@ -1109,13 +1097,24 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { | |||
1109 | #endif | 1097 | #endif |
1110 | }; | 1098 | }; |
1111 | 1099 | ||
1100 | static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index, | ||
1101 | enum v4l2_mbus_pixelcode *code) | ||
1102 | { | ||
1103 | if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts)) | ||
1104 | return -EINVAL; | ||
1105 | |||
1106 | *code = ov772x_cfmts[index].code; | ||
1107 | return 0; | ||
1108 | } | ||
1109 | |||
1112 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | 1110 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { |
1113 | .s_stream = ov772x_s_stream, | 1111 | .s_stream = ov772x_s_stream, |
1114 | .g_fmt = ov772x_g_fmt, | 1112 | .g_mbus_fmt = ov772x_g_fmt, |
1115 | .s_fmt = ov772x_s_fmt, | 1113 | .s_mbus_fmt = ov772x_s_fmt, |
1116 | .try_fmt = ov772x_try_fmt, | 1114 | .try_mbus_fmt = ov772x_try_fmt, |
1117 | .cropcap = ov772x_cropcap, | 1115 | .cropcap = ov772x_cropcap, |
1118 | .g_crop = ov772x_g_crop, | 1116 | .g_crop = ov772x_g_crop, |
1117 | .enum_mbus_fmt = ov772x_enum_fmt, | ||
1119 | }; | 1118 | }; |
1120 | 1119 | ||
1121 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | 1120 | static struct v4l2_subdev_ops ov772x_subdev_ops = { |
@@ -1143,10 +1142,10 @@ static int ov772x_probe(struct i2c_client *client, | |||
1143 | } | 1142 | } |
1144 | 1143 | ||
1145 | icl = to_soc_camera_link(icd); | 1144 | icl = to_soc_camera_link(icd); |
1146 | if (!icl) | 1145 | if (!icl || !icl->priv) |
1147 | return -EINVAL; | 1146 | return -EINVAL; |
1148 | 1147 | ||
1149 | info = container_of(icl, struct ov772x_camera_info, link); | 1148 | info = icl->priv; |
1150 | 1149 | ||
1151 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1150 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1152 | dev_err(&adapter->dev, | 1151 | dev_err(&adapter->dev, |
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index c81ae2192887..47bf60ceb7a2 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c | |||
@@ -154,19 +154,10 @@ static const struct ov9640_reg ov9640_regs_rgb[] = { | |||
154 | { OV9640_MTXS, 0x65 }, | 154 | { OV9640_MTXS, 0x65 }, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /* | 157 | static enum v4l2_mbus_pixelcode ov9640_codes[] = { |
158 | * TODO: this sensor also supports RGB555 and RGB565 formats, but support for | 158 | V4L2_MBUS_FMT_YUYV8_2X8_BE, |
159 | * them has not yet been sufficiently tested and so it is not included with | 159 | V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, |
160 | * this version of the driver. To test and debug these formats add two entries | 160 | V4L2_MBUS_FMT_RGB565_2X8_LE, |
161 | * to the below array, see ov722x.c for an example. | ||
162 | */ | ||
163 | static const struct soc_camera_data_format ov9640_fmt_lists[] = { | ||
164 | { | ||
165 | .name = "UYVY", | ||
166 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
167 | .depth = 16, | ||
168 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
169 | }, | ||
170 | }; | 161 | }; |
171 | 162 | ||
172 | static const struct v4l2_queryctrl ov9640_controls[] = { | 163 | static const struct v4l2_queryctrl ov9640_controls[] = { |
@@ -434,20 +425,22 @@ static void ov9640_res_roundup(u32 *width, u32 *height) | |||
434 | } | 425 | } |
435 | 426 | ||
436 | /* Prepare necessary register changes depending on color encoding */ | 427 | /* Prepare necessary register changes depending on color encoding */ |
437 | static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt) | 428 | static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code, |
429 | struct ov9640_reg_alt *alt) | ||
438 | { | 430 | { |
439 | switch (pixfmt) { | 431 | switch (code) { |
440 | case V4L2_PIX_FMT_UYVY: | 432 | default: |
433 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: | ||
441 | alt->com12 = OV9640_COM12_YUV_AVG; | 434 | alt->com12 = OV9640_COM12_YUV_AVG; |
442 | alt->com13 = OV9640_COM13_Y_DELAY_EN | | 435 | alt->com13 = OV9640_COM13_Y_DELAY_EN | |
443 | OV9640_COM13_YUV_DLY(0x01); | 436 | OV9640_COM13_YUV_DLY(0x01); |
444 | break; | 437 | break; |
445 | case V4L2_PIX_FMT_RGB555: | 438 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: |
446 | alt->com7 = OV9640_COM7_RGB; | 439 | alt->com7 = OV9640_COM7_RGB; |
447 | alt->com13 = OV9640_COM13_RGB_AVG; | 440 | alt->com13 = OV9640_COM13_RGB_AVG; |
448 | alt->com15 = OV9640_COM15_RGB_555; | 441 | alt->com15 = OV9640_COM15_RGB_555; |
449 | break; | 442 | break; |
450 | case V4L2_PIX_FMT_RGB565: | 443 | case V4L2_MBUS_FMT_RGB565_2X8_LE: |
451 | alt->com7 = OV9640_COM7_RGB; | 444 | alt->com7 = OV9640_COM7_RGB; |
452 | alt->com13 = OV9640_COM13_RGB_AVG; | 445 | alt->com13 = OV9640_COM13_RGB_AVG; |
453 | alt->com15 = OV9640_COM15_RGB_565; | 446 | alt->com15 = OV9640_COM15_RGB_565; |
@@ -456,8 +449,8 @@ static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt) | |||
456 | } | 449 | } |
457 | 450 | ||
458 | /* Setup registers according to resolution and color encoding */ | 451 | /* Setup registers according to resolution and color encoding */ |
459 | static int ov9640_write_regs(struct i2c_client *client, | 452 | static int ov9640_write_regs(struct i2c_client *client, u32 width, |
460 | u32 width, u32 pixfmt, struct ov9640_reg_alt *alts) | 453 | enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts) |
461 | { | 454 | { |
462 | const struct ov9640_reg *ov9640_regs, *matrix_regs; | 455 | const struct ov9640_reg *ov9640_regs, *matrix_regs; |
463 | int ov9640_regs_len, matrix_regs_len; | 456 | int ov9640_regs_len, matrix_regs_len; |
@@ -500,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client, | |||
500 | } | 493 | } |
501 | 494 | ||
502 | /* select color matrix configuration for given color encoding */ | 495 | /* select color matrix configuration for given color encoding */ |
503 | if (pixfmt == V4L2_PIX_FMT_UYVY) { | 496 | if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) { |
504 | matrix_regs = ov9640_regs_yuv; | 497 | matrix_regs = ov9640_regs_yuv; |
505 | matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); | 498 | matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); |
506 | } else { | 499 | } else { |
@@ -562,15 +555,17 @@ static int ov9640_prog_dflt(struct i2c_client *client) | |||
562 | } | 555 | } |
563 | 556 | ||
564 | /* set the format we will capture in */ | 557 | /* set the format we will capture in */ |
565 | static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 558 | static int ov9640_s_fmt(struct v4l2_subdev *sd, |
559 | struct v4l2_mbus_framefmt *mf) | ||
566 | { | 560 | { |
567 | struct i2c_client *client = sd->priv; | 561 | struct i2c_client *client = sd->priv; |
568 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
569 | struct ov9640_reg_alt alts = {0}; | 562 | struct ov9640_reg_alt alts = {0}; |
563 | enum v4l2_colorspace cspace; | ||
564 | enum v4l2_mbus_pixelcode code = mf->code; | ||
570 | int ret; | 565 | int ret; |
571 | 566 | ||
572 | ov9640_res_roundup(&pix->width, &pix->height); | 567 | ov9640_res_roundup(&mf->width, &mf->height); |
573 | ov9640_alter_regs(pix->pixelformat, &alts); | 568 | ov9640_alter_regs(mf->code, &alts); |
574 | 569 | ||
575 | ov9640_reset(client); | 570 | ov9640_reset(client); |
576 | 571 | ||
@@ -578,19 +573,57 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
578 | if (ret) | 573 | if (ret) |
579 | return ret; | 574 | return ret; |
580 | 575 | ||
581 | return ov9640_write_regs(client, pix->width, pix->pixelformat, &alts); | 576 | switch (code) { |
577 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: | ||
578 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
579 | cspace = V4L2_COLORSPACE_SRGB; | ||
580 | break; | ||
581 | default: | ||
582 | code = V4L2_MBUS_FMT_YUYV8_2X8_BE; | ||
583 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: | ||
584 | cspace = V4L2_COLORSPACE_JPEG; | ||
585 | } | ||
586 | |||
587 | ret = ov9640_write_regs(client, mf->width, code, &alts); | ||
588 | if (!ret) { | ||
589 | mf->code = code; | ||
590 | mf->colorspace = cspace; | ||
591 | } | ||
592 | |||
593 | return ret; | ||
582 | } | 594 | } |
583 | 595 | ||
584 | static int ov9640_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 596 | static int ov9640_try_fmt(struct v4l2_subdev *sd, |
597 | struct v4l2_mbus_framefmt *mf) | ||
585 | { | 598 | { |
586 | struct v4l2_pix_format *pix = &f->fmt.pix; | 599 | ov9640_res_roundup(&mf->width, &mf->height); |
587 | 600 | ||
588 | ov9640_res_roundup(&pix->width, &pix->height); | 601 | mf->field = V4L2_FIELD_NONE; |
589 | pix->field = V4L2_FIELD_NONE; | 602 | |
603 | switch (mf->code) { | ||
604 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: | ||
605 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
606 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
607 | break; | ||
608 | default: | ||
609 | mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; | ||
610 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: | ||
611 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
612 | } | ||
590 | 613 | ||
591 | return 0; | 614 | return 0; |
592 | } | 615 | } |
593 | 616 | ||
617 | static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index, | ||
618 | enum v4l2_mbus_pixelcode *code) | ||
619 | { | ||
620 | if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes)) | ||
621 | return -EINVAL; | ||
622 | |||
623 | *code = ov9640_codes[index]; | ||
624 | return 0; | ||
625 | } | ||
626 | |||
594 | static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 627 | static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
595 | { | 628 | { |
596 | a->c.left = 0; | 629 | a->c.left = 0; |
@@ -637,9 +670,6 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
637 | goto err; | 670 | goto err; |
638 | } | 671 | } |
639 | 672 | ||
640 | icd->formats = ov9640_fmt_lists; | ||
641 | icd->num_formats = ARRAY_SIZE(ov9640_fmt_lists); | ||
642 | |||
643 | /* | 673 | /* |
644 | * check and show product ID and manufacturer ID | 674 | * check and show product ID and manufacturer ID |
645 | */ | 675 | */ |
@@ -702,11 +732,12 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { | |||
702 | }; | 732 | }; |
703 | 733 | ||
704 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 734 | static struct v4l2_subdev_video_ops ov9640_video_ops = { |
705 | .s_stream = ov9640_s_stream, | 735 | .s_stream = ov9640_s_stream, |
706 | .s_fmt = ov9640_s_fmt, | 736 | .s_mbus_fmt = ov9640_s_fmt, |
707 | .try_fmt = ov9640_try_fmt, | 737 | .try_mbus_fmt = ov9640_try_fmt, |
708 | .cropcap = ov9640_cropcap, | 738 | .enum_mbus_fmt = ov9640_enum_fmt, |
709 | .g_crop = ov9640_g_crop, | 739 | .cropcap = ov9640_cropcap, |
740 | .g_crop = ov9640_g_crop, | ||
710 | 741 | ||
711 | }; | 742 | }; |
712 | 743 | ||
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 73ec970ca5ca..11a2c26399b5 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/version.h> | 32 | #include <linux/version.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <asm/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
36 | 36 | ||
37 | #include <linux/videodev2.h> | 37 | #include <linux/videodev2.h> |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 6aa48e0ae731..cc8ddb2d2382 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -151,17 +151,6 @@ static struct v4l2_format pvr_format [] = { | |||
151 | }; | 151 | }; |
152 | 152 | ||
153 | 153 | ||
154 | static const char *get_v4l_name(int v4l_type) | ||
155 | { | ||
156 | switch (v4l_type) { | ||
157 | case VFL_TYPE_GRABBER: return "video"; | ||
158 | case VFL_TYPE_RADIO: return "radio"; | ||
159 | case VFL_TYPE_VBI: return "vbi"; | ||
160 | default: return "?"; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | /* | 154 | /* |
166 | * pvr_ioctl() | 155 | * pvr_ioctl() |
167 | * | 156 | * |
@@ -891,10 +880,8 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
891 | 880 | ||
892 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | 881 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) |
893 | { | 882 | { |
894 | int num = dip->devbase.num; | ||
895 | struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; | 883 | struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; |
896 | enum pvr2_config cfg = dip->config; | 884 | enum pvr2_config cfg = dip->config; |
897 | int v4l_type = dip->v4l_type; | ||
898 | 885 | ||
899 | pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); | 886 | pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); |
900 | 887 | ||
@@ -906,8 +893,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | |||
906 | are gone. */ | 893 | are gone. */ |
907 | video_unregister_device(&dip->devbase); | 894 | video_unregister_device(&dip->devbase); |
908 | 895 | ||
909 | printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n", | 896 | printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n", |
910 | get_v4l_name(v4l_type), num, | 897 | video_device_node_name(&dip->devbase), |
911 | pvr2_config_get_name(cfg)); | 898 | pvr2_config_get_name(cfg)); |
912 | 899 | ||
913 | } | 900 | } |
@@ -1317,8 +1304,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | |||
1317 | ": Failed to register pvrusb2 v4l device\n"); | 1304 | ": Failed to register pvrusb2 v4l device\n"); |
1318 | } | 1305 | } |
1319 | 1306 | ||
1320 | printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n", | 1307 | printk(KERN_INFO "pvrusb2: registered device %s [%s]\n", |
1321 | get_v4l_name(dip->v4l_type), dip->devbase.num, | 1308 | video_device_node_name(&dip->devbase), |
1322 | pvr2_config_get_name(dip->config)); | 1309 | pvr2_config_get_name(dip->config)); |
1323 | 1310 | ||
1324 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, | 1311 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, |
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 89b620f6db7b..aea7e224cef6 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -169,7 +169,6 @@ static struct video_device pwc_template = { | |||
169 | .name = "Philips Webcam", /* Filled in later */ | 169 | .name = "Philips Webcam", /* Filled in later */ |
170 | .release = video_device_release, | 170 | .release = video_device_release, |
171 | .fops = &pwc_fops, | 171 | .fops = &pwc_fops, |
172 | .minor = -1, | ||
173 | }; | 172 | }; |
174 | 173 | ||
175 | /***************************************************************************/ | 174 | /***************************************************************************/ |
@@ -1807,7 +1806,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1807 | goto err_video_release; | 1806 | goto err_video_release; |
1808 | } | 1807 | } |
1809 | 1808 | ||
1810 | PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num); | 1809 | PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); |
1811 | 1810 | ||
1812 | /* occupy slot */ | 1811 | /* occupy slot */ |
1813 | if (hint < MAX_DEV_HINTS) | 1812 | if (hint < MAX_DEV_HINTS) |
@@ -1948,7 +1947,9 @@ MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, | |||
1948 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | 1947 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); |
1949 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); | 1948 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); |
1950 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); | 1949 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); |
1950 | #ifdef CONFIG_USB_PWC_DEBUG | ||
1951 | MODULE_PARM_DESC(trace, "For debugging purposes"); | 1951 | MODULE_PARM_DESC(trace, "For debugging purposes"); |
1952 | #endif | ||
1952 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); | 1953 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); |
1953 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); | 1954 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); |
1954 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | 1955 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 51b683c63b70..294f860ce2b0 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <media/v4l2-dev.h> | 32 | #include <media/v4l2-dev.h> |
33 | #include <media/videobuf-dma-sg.h> | 33 | #include <media/videobuf-dma-sg.h> |
34 | #include <media/soc_camera.h> | 34 | #include <media/soc_camera.h> |
35 | #include <media/soc_mediabus.h> | ||
35 | 36 | ||
36 | #include <linux/videodev2.h> | 37 | #include <linux/videodev2.h> |
37 | 38 | ||
@@ -183,23 +184,21 @@ struct pxa_cam_dma { | |||
183 | /* buffer for one video frame */ | 184 | /* buffer for one video frame */ |
184 | struct pxa_buffer { | 185 | struct pxa_buffer { |
185 | /* common v4l buffer stuff -- must be first */ | 186 | /* common v4l buffer stuff -- must be first */ |
186 | struct videobuf_buffer vb; | 187 | struct videobuf_buffer vb; |
187 | 188 | enum v4l2_mbus_pixelcode code; | |
188 | const struct soc_camera_data_format *fmt; | ||
189 | |||
190 | /* our descriptor lists for Y, U and V channels */ | 189 | /* our descriptor lists for Y, U and V channels */ |
191 | struct pxa_cam_dma dmas[3]; | 190 | struct pxa_cam_dma dmas[3]; |
192 | 191 | int inwork; | |
193 | int inwork; | 192 | enum pxa_camera_active_dma active_dma; |
194 | |||
195 | enum pxa_camera_active_dma active_dma; | ||
196 | }; | 193 | }; |
197 | 194 | ||
198 | struct pxa_camera_dev { | 195 | struct pxa_camera_dev { |
199 | struct soc_camera_host soc_host; | 196 | struct soc_camera_host soc_host; |
200 | /* PXA27x is only supposed to handle one camera on its Quick Capture | 197 | /* |
198 | * PXA27x is only supposed to handle one camera on its Quick Capture | ||
201 | * interface. If anyone ever builds hardware to enable more than | 199 | * interface. If anyone ever builds hardware to enable more than |
202 | * one camera, they will have to modify this driver too */ | 200 | * one camera, they will have to modify this driver too |
201 | */ | ||
203 | struct soc_camera_device *icd; | 202 | struct soc_camera_device *icd; |
204 | struct clk *clk; | 203 | struct clk *clk; |
205 | 204 | ||
@@ -241,11 +240,15 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
241 | unsigned int *size) | 240 | unsigned int *size) |
242 | { | 241 | { |
243 | struct soc_camera_device *icd = vq->priv_data; | 242 | struct soc_camera_device *icd = vq->priv_data; |
243 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
244 | icd->current_fmt->host_fmt); | ||
245 | |||
246 | if (bytes_per_line < 0) | ||
247 | return bytes_per_line; | ||
244 | 248 | ||
245 | dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); | 249 | dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); |
246 | 250 | ||
247 | *size = roundup(icd->user_width * icd->user_height * | 251 | *size = bytes_per_line * icd->user_height; |
248 | ((icd->current_fmt->depth + 7) >> 3), 8); | ||
249 | 252 | ||
250 | if (0 == *count) | 253 | if (0 == *count) |
251 | *count = 32; | 254 | *count = 32; |
@@ -267,8 +270,10 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | |||
267 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 270 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
268 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | 271 | &buf->vb, buf->vb.baddr, buf->vb.bsize); |
269 | 272 | ||
270 | /* This waits until this buffer is out of danger, i.e., until it is no | 273 | /* |
271 | * longer in STATE_QUEUED or STATE_ACTIVE */ | 274 | * This waits until this buffer is out of danger, i.e., until it is no |
275 | * longer in STATE_QUEUED or STATE_ACTIVE | ||
276 | */ | ||
272 | videobuf_waiton(&buf->vb, 0, 0); | 277 | videobuf_waiton(&buf->vb, 0, 0); |
273 | videobuf_dma_unmap(vq, dma); | 278 | videobuf_dma_unmap(vq, dma); |
274 | videobuf_dma_free(dma); | 279 | videobuf_dma_free(dma); |
@@ -429,6 +434,11 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
429 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 434 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
430 | int ret; | 435 | int ret; |
431 | int size_y, size_u = 0, size_v = 0; | 436 | int size_y, size_u = 0, size_v = 0; |
437 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
438 | icd->current_fmt->host_fmt); | ||
439 | |||
440 | if (bytes_per_line < 0) | ||
441 | return bytes_per_line; | ||
432 | 442 | ||
433 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 443 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
434 | vb, vb->baddr, vb->bsize); | 444 | vb, vb->baddr, vb->bsize); |
@@ -437,29 +447,33 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
437 | WARN_ON(!list_empty(&vb->queue)); | 447 | WARN_ON(!list_empty(&vb->queue)); |
438 | 448 | ||
439 | #ifdef DEBUG | 449 | #ifdef DEBUG |
440 | /* This can be useful if you want to see if we actually fill | 450 | /* |
441 | * the buffer with something */ | 451 | * This can be useful if you want to see if we actually fill |
452 | * the buffer with something | ||
453 | */ | ||
442 | memset((void *)vb->baddr, 0xaa, vb->bsize); | 454 | memset((void *)vb->baddr, 0xaa, vb->bsize); |
443 | #endif | 455 | #endif |
444 | 456 | ||
445 | BUG_ON(NULL == icd->current_fmt); | 457 | BUG_ON(NULL == icd->current_fmt); |
446 | 458 | ||
447 | /* I think, in buf_prepare you only have to protect global data, | 459 | /* |
448 | * the actual buffer is yours */ | 460 | * I think, in buf_prepare you only have to protect global data, |
461 | * the actual buffer is yours | ||
462 | */ | ||
449 | buf->inwork = 1; | 463 | buf->inwork = 1; |
450 | 464 | ||
451 | if (buf->fmt != icd->current_fmt || | 465 | if (buf->code != icd->current_fmt->code || |
452 | vb->width != icd->user_width || | 466 | vb->width != icd->user_width || |
453 | vb->height != icd->user_height || | 467 | vb->height != icd->user_height || |
454 | vb->field != field) { | 468 | vb->field != field) { |
455 | buf->fmt = icd->current_fmt; | 469 | buf->code = icd->current_fmt->code; |
456 | vb->width = icd->user_width; | 470 | vb->width = icd->user_width; |
457 | vb->height = icd->user_height; | 471 | vb->height = icd->user_height; |
458 | vb->field = field; | 472 | vb->field = field; |
459 | vb->state = VIDEOBUF_NEEDS_INIT; | 473 | vb->state = VIDEOBUF_NEEDS_INIT; |
460 | } | 474 | } |
461 | 475 | ||
462 | vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); | 476 | vb->size = bytes_per_line * vb->height; |
463 | if (0 != vb->baddr && vb->bsize < vb->size) { | 477 | if (0 != vb->baddr && vb->bsize < vb->size) { |
464 | ret = -EINVAL; | 478 | ret = -EINVAL; |
465 | goto out; | 479 | goto out; |
@@ -834,8 +848,10 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q, | |||
834 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 848 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
835 | struct pxa_camera_dev *pcdev = ici->priv; | 849 | struct pxa_camera_dev *pcdev = ici->priv; |
836 | 850 | ||
837 | /* We must pass NULL as dev pointer, then all pci_* dma operations | 851 | /* |
838 | * transform to normal dma_* ones. */ | 852 | * We must pass NULL as dev pointer, then all pci_* dma operations |
853 | * transform to normal dma_* ones. | ||
854 | */ | ||
839 | videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, | 855 | videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, |
840 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | 856 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, |
841 | sizeof(struct pxa_buffer), icd); | 857 | sizeof(struct pxa_buffer), icd); |
@@ -1051,11 +1067,18 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1051 | { | 1067 | { |
1052 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1068 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1053 | struct pxa_camera_dev *pcdev = ici->priv; | 1069 | struct pxa_camera_dev *pcdev = ici->priv; |
1070 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1054 | unsigned long dw, bpp; | 1071 | unsigned long dw, bpp; |
1055 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; | 1072 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; |
1073 | int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top); | ||
1074 | |||
1075 | if (ret < 0) | ||
1076 | y_skip_top = 0; | ||
1056 | 1077 | ||
1057 | /* Datawidth is now guaranteed to be equal to one of the three values. | 1078 | /* |
1058 | * We fix bit-per-pixel equal to data-width... */ | 1079 | * Datawidth is now guaranteed to be equal to one of the three values. |
1080 | * We fix bit-per-pixel equal to data-width... | ||
1081 | */ | ||
1059 | switch (flags & SOCAM_DATAWIDTH_MASK) { | 1082 | switch (flags & SOCAM_DATAWIDTH_MASK) { |
1060 | case SOCAM_DATAWIDTH_10: | 1083 | case SOCAM_DATAWIDTH_10: |
1061 | dw = 4; | 1084 | dw = 4; |
@@ -1066,8 +1089,10 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1066 | bpp = 0x20; | 1089 | bpp = 0x20; |
1067 | break; | 1090 | break; |
1068 | default: | 1091 | default: |
1069 | /* Actually it can only be 8 now, | 1092 | /* |
1070 | * default is just to silence compiler warnings */ | 1093 | * Actually it can only be 8 now, |
1094 | * default is just to silence compiler warnings | ||
1095 | */ | ||
1071 | case SOCAM_DATAWIDTH_8: | 1096 | case SOCAM_DATAWIDTH_8: |
1072 | dw = 2; | 1097 | dw = 2; |
1073 | bpp = 0; | 1098 | bpp = 0; |
@@ -1118,7 +1143,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1118 | 1143 | ||
1119 | cicr2 = 0; | 1144 | cicr2 = 0; |
1120 | cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | | 1145 | cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | |
1121 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); | 1146 | CICR3_BFW_VAL(min((u32)255, y_skip_top)); |
1122 | cicr4 |= pcdev->mclk_divisor; | 1147 | cicr4 |= pcdev->mclk_divisor; |
1123 | 1148 | ||
1124 | __raw_writel(cicr1, pcdev->base + CICR1); | 1149 | __raw_writel(cicr1, pcdev->base + CICR1); |
@@ -1138,9 +1163,15 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1138 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1163 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1139 | struct pxa_camera_dev *pcdev = ici->priv; | 1164 | struct pxa_camera_dev *pcdev = ici->priv; |
1140 | unsigned long bus_flags, camera_flags, common_flags; | 1165 | unsigned long bus_flags, camera_flags, common_flags; |
1141 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | 1166 | const struct soc_mbus_pixelfmt *fmt; |
1167 | int ret; | ||
1142 | struct pxa_cam *cam = icd->host_priv; | 1168 | struct pxa_cam *cam = icd->host_priv; |
1143 | 1169 | ||
1170 | fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); | ||
1171 | if (!fmt) | ||
1172 | return -EINVAL; | ||
1173 | |||
1174 | ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags); | ||
1144 | if (ret < 0) | 1175 | if (ret < 0) |
1145 | return ret; | 1176 | return ret; |
1146 | 1177 | ||
@@ -1204,59 +1235,49 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | |||
1204 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | 1235 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; |
1205 | } | 1236 | } |
1206 | 1237 | ||
1207 | static const struct soc_camera_data_format pxa_camera_formats[] = { | 1238 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { |
1208 | { | 1239 | { |
1209 | .name = "Planar YUV422 16 bit", | 1240 | .fourcc = V4L2_PIX_FMT_YUV422P, |
1210 | .depth = 16, | 1241 | .name = "Planar YUV422 16 bit", |
1211 | .fourcc = V4L2_PIX_FMT_YUV422P, | 1242 | .bits_per_sample = 8, |
1212 | .colorspace = V4L2_COLORSPACE_JPEG, | 1243 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1244 | .order = SOC_MBUS_ORDER_LE, | ||
1213 | }, | 1245 | }, |
1214 | }; | 1246 | }; |
1215 | 1247 | ||
1216 | static bool buswidth_supported(struct soc_camera_device *icd, int depth) | 1248 | /* This will be corrected as we get more formats */ |
1249 | static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
1217 | { | 1250 | { |
1218 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1251 | return fmt->packing == SOC_MBUS_PACKING_NONE || |
1219 | struct pxa_camera_dev *pcdev = ici->priv; | 1252 | (fmt->bits_per_sample == 8 && |
1220 | 1253 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | |
1221 | switch (depth) { | 1254 | (fmt->bits_per_sample > 8 && |
1222 | case 8: | 1255 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
1223 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8); | ||
1224 | case 9: | ||
1225 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9); | ||
1226 | case 10: | ||
1227 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10); | ||
1228 | } | ||
1229 | return false; | ||
1230 | } | ||
1231 | |||
1232 | static int required_buswidth(const struct soc_camera_data_format *fmt) | ||
1233 | { | ||
1234 | switch (fmt->fourcc) { | ||
1235 | case V4L2_PIX_FMT_UYVY: | ||
1236 | case V4L2_PIX_FMT_VYUY: | ||
1237 | case V4L2_PIX_FMT_YUYV: | ||
1238 | case V4L2_PIX_FMT_YVYU: | ||
1239 | case V4L2_PIX_FMT_RGB565: | ||
1240 | case V4L2_PIX_FMT_RGB555: | ||
1241 | return 8; | ||
1242 | default: | ||
1243 | return fmt->depth; | ||
1244 | } | ||
1245 | } | 1256 | } |
1246 | 1257 | ||
1247 | static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | 1258 | static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, |
1248 | struct soc_camera_format_xlate *xlate) | 1259 | struct soc_camera_format_xlate *xlate) |
1249 | { | 1260 | { |
1261 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1250 | struct device *dev = icd->dev.parent; | 1262 | struct device *dev = icd->dev.parent; |
1251 | int formats = 0, buswidth, ret; | 1263 | int formats = 0, ret; |
1252 | struct pxa_cam *cam; | 1264 | struct pxa_cam *cam; |
1265 | enum v4l2_mbus_pixelcode code; | ||
1266 | const struct soc_mbus_pixelfmt *fmt; | ||
1253 | 1267 | ||
1254 | buswidth = required_buswidth(icd->formats + idx); | 1268 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); |
1269 | if (ret < 0) | ||
1270 | /* No more formats */ | ||
1271 | return 0; | ||
1255 | 1272 | ||
1256 | if (!buswidth_supported(icd, buswidth)) | 1273 | fmt = soc_mbus_get_fmtdesc(code); |
1274 | if (!fmt) { | ||
1275 | dev_err(dev, "Invalid format code #%d: %d\n", idx, code); | ||
1257 | return 0; | 1276 | return 0; |
1277 | } | ||
1258 | 1278 | ||
1259 | ret = pxa_camera_try_bus_param(icd, buswidth); | 1279 | /* This also checks support for the requested bits-per-sample */ |
1280 | ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
1260 | if (ret < 0) | 1281 | if (ret < 0) |
1261 | return 0; | 1282 | return 0; |
1262 | 1283 | ||
@@ -1270,45 +1291,40 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1270 | cam = icd->host_priv; | 1291 | cam = icd->host_priv; |
1271 | } | 1292 | } |
1272 | 1293 | ||
1273 | switch (icd->formats[idx].fourcc) { | 1294 | switch (code) { |
1274 | case V4L2_PIX_FMT_UYVY: | 1295 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
1275 | formats++; | 1296 | formats++; |
1276 | if (xlate) { | 1297 | if (xlate) { |
1277 | xlate->host_fmt = &pxa_camera_formats[0]; | 1298 | xlate->host_fmt = &pxa_camera_formats[0]; |
1278 | xlate->cam_fmt = icd->formats + idx; | 1299 | xlate->code = code; |
1279 | xlate->buswidth = buswidth; | ||
1280 | xlate++; | 1300 | xlate++; |
1281 | dev_dbg(dev, "Providing format %s using %s\n", | 1301 | dev_dbg(dev, "Providing format %s using code %d\n", |
1282 | pxa_camera_formats[0].name, | 1302 | pxa_camera_formats[0].name, code); |
1283 | icd->formats[idx].name); | ||
1284 | } | 1303 | } |
1285 | case V4L2_PIX_FMT_VYUY: | 1304 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
1286 | case V4L2_PIX_FMT_YUYV: | 1305 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
1287 | case V4L2_PIX_FMT_YVYU: | 1306 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
1288 | case V4L2_PIX_FMT_RGB565: | 1307 | case V4L2_MBUS_FMT_RGB565_2X8_LE: |
1289 | case V4L2_PIX_FMT_RGB555: | 1308 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: |
1290 | formats++; | 1309 | if (xlate) |
1291 | if (xlate) { | ||
1292 | xlate->host_fmt = icd->formats + idx; | ||
1293 | xlate->cam_fmt = icd->formats + idx; | ||
1294 | xlate->buswidth = buswidth; | ||
1295 | xlate++; | ||
1296 | dev_dbg(dev, "Providing format %s packed\n", | 1310 | dev_dbg(dev, "Providing format %s packed\n", |
1297 | icd->formats[idx].name); | 1311 | fmt->name); |
1298 | } | ||
1299 | break; | 1312 | break; |
1300 | default: | 1313 | default: |
1301 | /* Generic pass-through */ | 1314 | if (!pxa_camera_packing_supported(fmt)) |
1302 | formats++; | 1315 | return 0; |
1303 | if (xlate) { | 1316 | if (xlate) |
1304 | xlate->host_fmt = icd->formats + idx; | ||
1305 | xlate->cam_fmt = icd->formats + idx; | ||
1306 | xlate->buswidth = icd->formats[idx].depth; | ||
1307 | xlate++; | ||
1308 | dev_dbg(dev, | 1317 | dev_dbg(dev, |
1309 | "Providing format %s in pass-through mode\n", | 1318 | "Providing format %s in pass-through mode\n", |
1310 | icd->formats[idx].name); | 1319 | fmt->name); |
1311 | } | 1320 | } |
1321 | |||
1322 | /* Generic pass-through */ | ||
1323 | formats++; | ||
1324 | if (xlate) { | ||
1325 | xlate->host_fmt = fmt; | ||
1326 | xlate->code = code; | ||
1327 | xlate++; | ||
1312 | } | 1328 | } |
1313 | 1329 | ||
1314 | return formats; | 1330 | return formats; |
@@ -1320,11 +1336,11 @@ static void pxa_camera_put_formats(struct soc_camera_device *icd) | |||
1320 | icd->host_priv = NULL; | 1336 | icd->host_priv = NULL; |
1321 | } | 1337 | } |
1322 | 1338 | ||
1323 | static int pxa_camera_check_frame(struct v4l2_pix_format *pix) | 1339 | static int pxa_camera_check_frame(u32 width, u32 height) |
1324 | { | 1340 | { |
1325 | /* limit to pxa hardware capabilities */ | 1341 | /* limit to pxa hardware capabilities */ |
1326 | return pix->height < 32 || pix->height > 2048 || pix->width < 48 || | 1342 | return height < 32 || height > 2048 || width < 48 || width > 2048 || |
1327 | pix->width > 2048 || (pix->width & 0x01); | 1343 | (width & 0x01); |
1328 | } | 1344 | } |
1329 | 1345 | ||
1330 | static int pxa_camera_set_crop(struct soc_camera_device *icd, | 1346 | static int pxa_camera_set_crop(struct soc_camera_device *icd, |
@@ -1339,9 +1355,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, | |||
1339 | .master_clock = pcdev->mclk, | 1355 | .master_clock = pcdev->mclk, |
1340 | .pixel_clock_max = pcdev->ciclk / 4, | 1356 | .pixel_clock_max = pcdev->ciclk / 4, |
1341 | }; | 1357 | }; |
1342 | struct v4l2_format f; | 1358 | struct v4l2_mbus_framefmt mf; |
1343 | struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp; | ||
1344 | struct pxa_cam *cam = icd->host_priv; | 1359 | struct pxa_cam *cam = icd->host_priv; |
1360 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | ||
1345 | int ret; | 1361 | int ret; |
1346 | 1362 | ||
1347 | /* If PCLK is used to latch data from the sensor, check sense */ | 1363 | /* If PCLK is used to latch data from the sensor, check sense */ |
@@ -1358,27 +1374,23 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, | |||
1358 | return ret; | 1374 | return ret; |
1359 | } | 1375 | } |
1360 | 1376 | ||
1361 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1377 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
1362 | |||
1363 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1364 | if (ret < 0) | 1378 | if (ret < 0) |
1365 | return ret; | 1379 | return ret; |
1366 | 1380 | ||
1367 | pix_tmp = *pix; | 1381 | if (pxa_camera_check_frame(mf.width, mf.height)) { |
1368 | if (pxa_camera_check_frame(pix)) { | ||
1369 | /* | 1382 | /* |
1370 | * Camera cropping produced a frame beyond our capabilities. | 1383 | * Camera cropping produced a frame beyond our capabilities. |
1371 | * FIXME: just extract a subframe, that we can process. | 1384 | * FIXME: just extract a subframe, that we can process. |
1372 | */ | 1385 | */ |
1373 | v4l_bound_align_image(&pix->width, 48, 2048, 1, | 1386 | v4l_bound_align_image(&mf.width, 48, 2048, 1, |
1374 | &pix->height, 32, 2048, 0, | 1387 | &mf.height, 32, 2048, 0, |
1375 | icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? | 1388 | fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); |
1376 | 4 : 0); | 1389 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); |
1377 | ret = v4l2_subdev_call(sd, video, s_fmt, &f); | ||
1378 | if (ret < 0) | 1390 | if (ret < 0) |
1379 | return ret; | 1391 | return ret; |
1380 | 1392 | ||
1381 | if (pxa_camera_check_frame(pix)) { | 1393 | if (pxa_camera_check_frame(mf.width, mf.height)) { |
1382 | dev_warn(icd->dev.parent, | 1394 | dev_warn(icd->dev.parent, |
1383 | "Inconsistent state. Use S_FMT to repair\n"); | 1395 | "Inconsistent state. Use S_FMT to repair\n"); |
1384 | return -EINVAL; | 1396 | return -EINVAL; |
@@ -1395,10 +1407,10 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, | |||
1395 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | 1407 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); |
1396 | } | 1408 | } |
1397 | 1409 | ||
1398 | icd->user_width = pix->width; | 1410 | icd->user_width = mf.width; |
1399 | icd->user_height = pix->height; | 1411 | icd->user_height = mf.height; |
1400 | 1412 | ||
1401 | pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc); | 1413 | pxa_camera_setup_cicr(icd, cam->flags, fourcc); |
1402 | 1414 | ||
1403 | return ret; | 1415 | return ret; |
1404 | } | 1416 | } |
@@ -1410,14 +1422,13 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1410 | struct pxa_camera_dev *pcdev = ici->priv; | 1422 | struct pxa_camera_dev *pcdev = ici->priv; |
1411 | struct device *dev = icd->dev.parent; | 1423 | struct device *dev = icd->dev.parent; |
1412 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1424 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1413 | const struct soc_camera_data_format *cam_fmt = NULL; | ||
1414 | const struct soc_camera_format_xlate *xlate = NULL; | 1425 | const struct soc_camera_format_xlate *xlate = NULL; |
1415 | struct soc_camera_sense sense = { | 1426 | struct soc_camera_sense sense = { |
1416 | .master_clock = pcdev->mclk, | 1427 | .master_clock = pcdev->mclk, |
1417 | .pixel_clock_max = pcdev->ciclk / 4, | 1428 | .pixel_clock_max = pcdev->ciclk / 4, |
1418 | }; | 1429 | }; |
1419 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1430 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1420 | struct v4l2_format cam_f = *f; | 1431 | struct v4l2_mbus_framefmt mf; |
1421 | int ret; | 1432 | int ret; |
1422 | 1433 | ||
1423 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 1434 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
@@ -1426,26 +1437,31 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1426 | return -EINVAL; | 1437 | return -EINVAL; |
1427 | } | 1438 | } |
1428 | 1439 | ||
1429 | cam_fmt = xlate->cam_fmt; | ||
1430 | |||
1431 | /* If PCLK is used to latch data from the sensor, check sense */ | 1440 | /* If PCLK is used to latch data from the sensor, check sense */ |
1432 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | 1441 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) |
1442 | /* The caller holds a mutex. */ | ||
1433 | icd->sense = &sense; | 1443 | icd->sense = &sense; |
1434 | 1444 | ||
1435 | cam_f.fmt.pix.pixelformat = cam_fmt->fourcc; | 1445 | mf.width = pix->width; |
1436 | ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f); | 1446 | mf.height = pix->height; |
1437 | cam_f.fmt.pix.pixelformat = pix->pixelformat; | 1447 | mf.field = pix->field; |
1438 | *pix = cam_f.fmt.pix; | 1448 | mf.colorspace = pix->colorspace; |
1449 | mf.code = xlate->code; | ||
1450 | |||
1451 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
1452 | |||
1453 | if (mf.code != xlate->code) | ||
1454 | return -EINVAL; | ||
1439 | 1455 | ||
1440 | icd->sense = NULL; | 1456 | icd->sense = NULL; |
1441 | 1457 | ||
1442 | if (ret < 0) { | 1458 | if (ret < 0) { |
1443 | dev_warn(dev, "Failed to configure for format %x\n", | 1459 | dev_warn(dev, "Failed to configure for format %x\n", |
1444 | pix->pixelformat); | 1460 | pix->pixelformat); |
1445 | } else if (pxa_camera_check_frame(pix)) { | 1461 | } else if (pxa_camera_check_frame(mf.width, mf.height)) { |
1446 | dev_warn(dev, | 1462 | dev_warn(dev, |
1447 | "Camera driver produced an unsupported frame %dx%d\n", | 1463 | "Camera driver produced an unsupported frame %dx%d\n", |
1448 | pix->width, pix->height); | 1464 | mf.width, mf.height); |
1449 | ret = -EINVAL; | 1465 | ret = -EINVAL; |
1450 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | 1466 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { |
1451 | if (sense.pixel_clock > sense.pixel_clock_max) { | 1467 | if (sense.pixel_clock > sense.pixel_clock_max) { |
@@ -1457,10 +1473,14 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1457 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | 1473 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); |
1458 | } | 1474 | } |
1459 | 1475 | ||
1460 | if (!ret) { | 1476 | if (ret < 0) |
1461 | icd->buswidth = xlate->buswidth; | 1477 | return ret; |
1462 | icd->current_fmt = xlate->host_fmt; | 1478 | |
1463 | } | 1479 | pix->width = mf.width; |
1480 | pix->height = mf.height; | ||
1481 | pix->field = mf.field; | ||
1482 | pix->colorspace = mf.colorspace; | ||
1483 | icd->current_fmt = xlate; | ||
1464 | 1484 | ||
1465 | return ret; | 1485 | return ret; |
1466 | } | 1486 | } |
@@ -1468,17 +1488,16 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1468 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, | 1488 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, |
1469 | struct v4l2_format *f) | 1489 | struct v4l2_format *f) |
1470 | { | 1490 | { |
1471 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1472 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1491 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1473 | const struct soc_camera_format_xlate *xlate; | 1492 | const struct soc_camera_format_xlate *xlate; |
1474 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1493 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1494 | struct v4l2_mbus_framefmt mf; | ||
1475 | __u32 pixfmt = pix->pixelformat; | 1495 | __u32 pixfmt = pix->pixelformat; |
1476 | enum v4l2_field field; | ||
1477 | int ret; | 1496 | int ret; |
1478 | 1497 | ||
1479 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1498 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
1480 | if (!xlate) { | 1499 | if (!xlate) { |
1481 | dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt); | 1500 | dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); |
1482 | return -EINVAL; | 1501 | return -EINVAL; |
1483 | } | 1502 | } |
1484 | 1503 | ||
@@ -1492,22 +1511,36 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1492 | &pix->height, 32, 2048, 0, | 1511 | &pix->height, 32, 2048, 0, |
1493 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); | 1512 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); |
1494 | 1513 | ||
1495 | pix->bytesperline = pix->width * | 1514 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, |
1496 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 1515 | xlate->host_fmt); |
1516 | if (pix->bytesperline < 0) | ||
1517 | return pix->bytesperline; | ||
1497 | pix->sizeimage = pix->height * pix->bytesperline; | 1518 | pix->sizeimage = pix->height * pix->bytesperline; |
1498 | 1519 | ||
1499 | /* camera has to see its format, but the user the original one */ | ||
1500 | pix->pixelformat = xlate->cam_fmt->fourcc; | ||
1501 | /* limit to sensor capabilities */ | 1520 | /* limit to sensor capabilities */ |
1502 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 1521 | mf.width = pix->width; |
1503 | pix->pixelformat = pixfmt; | 1522 | mf.height = pix->height; |
1523 | mf.field = pix->field; | ||
1524 | mf.colorspace = pix->colorspace; | ||
1525 | mf.code = xlate->code; | ||
1504 | 1526 | ||
1505 | field = pix->field; | 1527 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); |
1528 | if (ret < 0) | ||
1529 | return ret; | ||
1506 | 1530 | ||
1507 | if (field == V4L2_FIELD_ANY) { | 1531 | pix->width = mf.width; |
1508 | pix->field = V4L2_FIELD_NONE; | 1532 | pix->height = mf.height; |
1509 | } else if (field != V4L2_FIELD_NONE) { | 1533 | pix->colorspace = mf.colorspace; |
1510 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); | 1534 | |
1535 | switch (mf.field) { | ||
1536 | case V4L2_FIELD_ANY: | ||
1537 | case V4L2_FIELD_NONE: | ||
1538 | pix->field = V4L2_FIELD_NONE; | ||
1539 | break; | ||
1540 | default: | ||
1541 | /* TODO: support interlaced at least in pass-through mode */ | ||
1542 | dev_err(icd->dev.parent, "Field type %d unsupported.\n", | ||
1543 | mf.field); | ||
1511 | return -EINVAL; | 1544 | return -EINVAL; |
1512 | } | 1545 | } |
1513 | 1546 | ||
@@ -1519,10 +1552,12 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf, | |||
1519 | { | 1552 | { |
1520 | int i; | 1553 | int i; |
1521 | 1554 | ||
1522 | /* This is for locking debugging only. I removed spinlocks and now I | 1555 | /* |
1556 | * This is for locking debugging only. I removed spinlocks and now I | ||
1523 | * check whether .prepare is ever called on a linked buffer, or whether | 1557 | * check whether .prepare is ever called on a linked buffer, or whether |
1524 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | 1558 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now |
1525 | * it hadn't triggered */ | 1559 | * it hadn't triggered |
1560 | */ | ||
1526 | for (i = 0; i < p->count; i++) { | 1561 | for (i = 0; i < p->count; i++) { |
1527 | struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i], | 1562 | struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i], |
1528 | struct pxa_buffer, vb); | 1563 | struct pxa_buffer, vb); |
@@ -1657,8 +1692,10 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
1657 | pcdev->platform_flags = pcdev->pdata->flags; | 1692 | pcdev->platform_flags = pcdev->pdata->flags; |
1658 | if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | | 1693 | if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | |
1659 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { | 1694 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { |
1660 | /* Platform hasn't set available data widths. This is bad. | 1695 | /* |
1661 | * Warn and use a default. */ | 1696 | * Platform hasn't set available data widths. This is bad. |
1697 | * Warn and use a default. | ||
1698 | */ | ||
1662 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | 1699 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " |
1663 | "data widths, using default 10 bit\n"); | 1700 | "data widths, using default 10 bit\n"); |
1664 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; | 1701 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; |
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 373f2a30a677..7e42989ce0e4 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c | |||
@@ -13,9 +13,11 @@ | |||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/videodev2.h> | 14 | #include <linux/videodev2.h> |
15 | 15 | ||
16 | #include <media/rj54n1cb0c.h> | ||
17 | #include <media/soc_camera.h> | ||
18 | #include <media/soc_mediabus.h> | ||
16 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | ||
19 | 21 | ||
20 | #define RJ54N1_DEV_CODE 0x0400 | 22 | #define RJ54N1_DEV_CODE 0x0400 |
21 | #define RJ54N1_DEV_CODE2 0x0401 | 23 | #define RJ54N1_DEV_CODE2 0x0401 |
@@ -38,6 +40,7 @@ | |||
38 | #define RJ54N1_H_OBEN_OFS 0x0413 | 40 | #define RJ54N1_H_OBEN_OFS 0x0413 |
39 | #define RJ54N1_V_OBEN_OFS 0x0414 | 41 | #define RJ54N1_V_OBEN_OFS 0x0414 |
40 | #define RJ54N1_RESIZE_CONTROL 0x0415 | 42 | #define RJ54N1_RESIZE_CONTROL 0x0415 |
43 | #define RJ54N1_STILL_CONTROL 0x0417 | ||
41 | #define RJ54N1_INC_USE_SEL_H 0x0425 | 44 | #define RJ54N1_INC_USE_SEL_H 0x0425 |
42 | #define RJ54N1_INC_USE_SEL_L 0x0426 | 45 | #define RJ54N1_INC_USE_SEL_L 0x0426 |
43 | #define RJ54N1_MIRROR_STILL_MODE 0x0427 | 46 | #define RJ54N1_MIRROR_STILL_MODE 0x0427 |
@@ -49,10 +52,21 @@ | |||
49 | #define RJ54N1_RA_SEL_UL 0x0530 | 52 | #define RJ54N1_RA_SEL_UL 0x0530 |
50 | #define RJ54N1_BYTE_SWAP 0x0531 | 53 | #define RJ54N1_BYTE_SWAP 0x0531 |
51 | #define RJ54N1_OUT_SIGPO 0x053b | 54 | #define RJ54N1_OUT_SIGPO 0x053b |
55 | #define RJ54N1_WB_SEL_WEIGHT_I 0x054e | ||
56 | #define RJ54N1_BIT8_WB 0x0569 | ||
57 | #define RJ54N1_HCAPS_WB 0x056a | ||
58 | #define RJ54N1_VCAPS_WB 0x056b | ||
59 | #define RJ54N1_HCAPE_WB 0x056c | ||
60 | #define RJ54N1_VCAPE_WB 0x056d | ||
61 | #define RJ54N1_EXPOSURE_CONTROL 0x058c | ||
52 | #define RJ54N1_FRAME_LENGTH_S_H 0x0595 | 62 | #define RJ54N1_FRAME_LENGTH_S_H 0x0595 |
53 | #define RJ54N1_FRAME_LENGTH_S_L 0x0596 | 63 | #define RJ54N1_FRAME_LENGTH_S_L 0x0596 |
54 | #define RJ54N1_FRAME_LENGTH_P_H 0x0597 | 64 | #define RJ54N1_FRAME_LENGTH_P_H 0x0597 |
55 | #define RJ54N1_FRAME_LENGTH_P_L 0x0598 | 65 | #define RJ54N1_FRAME_LENGTH_P_L 0x0598 |
66 | #define RJ54N1_PEAK_H 0x05b7 | ||
67 | #define RJ54N1_PEAK_50 0x05b8 | ||
68 | #define RJ54N1_PEAK_60 0x05b9 | ||
69 | #define RJ54N1_PEAK_DIFF 0x05ba | ||
56 | #define RJ54N1_IOC 0x05ef | 70 | #define RJ54N1_IOC 0x05ef |
57 | #define RJ54N1_TG_BYPASS 0x0700 | 71 | #define RJ54N1_TG_BYPASS 0x0700 |
58 | #define RJ54N1_PLL_L 0x0701 | 72 | #define RJ54N1_PLL_L 0x0701 |
@@ -68,6 +82,7 @@ | |||
68 | #define RJ54N1_OCLK_SEL_EN 0x0713 | 82 | #define RJ54N1_OCLK_SEL_EN 0x0713 |
69 | #define RJ54N1_CLK_RST 0x0717 | 83 | #define RJ54N1_CLK_RST 0x0717 |
70 | #define RJ54N1_RESET_STANDBY 0x0718 | 84 | #define RJ54N1_RESET_STANDBY 0x0718 |
85 | #define RJ54N1_FWFLG 0x07fe | ||
71 | 86 | ||
72 | #define E_EXCLK (1 << 7) | 87 | #define E_EXCLK (1 << 7) |
73 | #define SOFT_STDBY (1 << 4) | 88 | #define SOFT_STDBY (1 << 4) |
@@ -78,29 +93,53 @@ | |||
78 | #define RESIZE_HOLD_SEL (1 << 2) | 93 | #define RESIZE_HOLD_SEL (1 << 2) |
79 | #define RESIZE_GO (1 << 1) | 94 | #define RESIZE_GO (1 << 1) |
80 | 95 | ||
96 | /* | ||
97 | * When cropping, the camera automatically centers the cropped region, there | ||
98 | * doesn't seem to be a way to specify an explicit location of the rectangle. | ||
99 | */ | ||
81 | #define RJ54N1_COLUMN_SKIP 0 | 100 | #define RJ54N1_COLUMN_SKIP 0 |
82 | #define RJ54N1_ROW_SKIP 0 | 101 | #define RJ54N1_ROW_SKIP 0 |
83 | #define RJ54N1_MAX_WIDTH 1600 | 102 | #define RJ54N1_MAX_WIDTH 1600 |
84 | #define RJ54N1_MAX_HEIGHT 1200 | 103 | #define RJ54N1_MAX_HEIGHT 1200 |
85 | 104 | ||
105 | #define PLL_L 2 | ||
106 | #define PLL_N 0x31 | ||
107 | |||
86 | /* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ | 108 | /* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ |
87 | 109 | ||
88 | static const struct soc_camera_data_format rj54n1_colour_formats[] = { | 110 | /* RJ54N1CB0C has only one fixed colorspace per pixelcode */ |
89 | { | 111 | struct rj54n1_datafmt { |
90 | .name = "YUYV", | 112 | enum v4l2_mbus_pixelcode code; |
91 | .depth = 16, | 113 | enum v4l2_colorspace colorspace; |
92 | .fourcc = V4L2_PIX_FMT_YUYV, | 114 | }; |
93 | .colorspace = V4L2_COLORSPACE_JPEG, | 115 | |
94 | }, { | 116 | /* Find a data format by a pixel code in an array */ |
95 | .name = "RGB565", | 117 | static const struct rj54n1_datafmt *rj54n1_find_datafmt( |
96 | .depth = 16, | 118 | enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt, |
97 | .fourcc = V4L2_PIX_FMT_RGB565, | 119 | int n) |
98 | .colorspace = V4L2_COLORSPACE_SRGB, | 120 | { |
99 | } | 121 | int i; |
122 | for (i = 0; i < n; i++) | ||
123 | if (fmt[i].code == code) | ||
124 | return fmt + i; | ||
125 | |||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | static const struct rj54n1_datafmt rj54n1_colour_fmts[] = { | ||
130 | {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
131 | {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG}, | ||
132 | {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, | ||
133 | {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, | ||
134 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, | ||
135 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB}, | ||
136 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, | ||
137 | {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB}, | ||
138 | {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, | ||
100 | }; | 139 | }; |
101 | 140 | ||
102 | struct rj54n1_clock_div { | 141 | struct rj54n1_clock_div { |
103 | u8 ratio_tg; | 142 | u8 ratio_tg; /* can be 0 or an odd number */ |
104 | u8 ratio_t; | 143 | u8 ratio_t; |
105 | u8 ratio_r; | 144 | u8 ratio_r; |
106 | u8 ratio_op; | 145 | u8 ratio_op; |
@@ -109,12 +148,14 @@ struct rj54n1_clock_div { | |||
109 | 148 | ||
110 | struct rj54n1 { | 149 | struct rj54n1 { |
111 | struct v4l2_subdev subdev; | 150 | struct v4l2_subdev subdev; |
151 | struct rj54n1_clock_div clk_div; | ||
152 | const struct rj54n1_datafmt *fmt; | ||
112 | struct v4l2_rect rect; /* Sensor window */ | 153 | struct v4l2_rect rect; /* Sensor window */ |
154 | unsigned int tgclk_mhz; | ||
155 | bool auto_wb; | ||
113 | unsigned short width; /* Output window */ | 156 | unsigned short width; /* Output window */ |
114 | unsigned short height; | 157 | unsigned short height; |
115 | unsigned short resize; /* Sensor * 1024 / resize = Output */ | 158 | unsigned short resize; /* Sensor * 1024 / resize = Output */ |
116 | struct rj54n1_clock_div clk_div; | ||
117 | u32 fourcc; | ||
118 | unsigned short scale; | 159 | unsigned short scale; |
119 | u8 bank; | 160 | u8 bank; |
120 | }; | 161 | }; |
@@ -171,7 +212,7 @@ const static struct rj54n1_reg_val bank_7[] = { | |||
171 | {0x714, 0xff}, | 212 | {0x714, 0xff}, |
172 | {0x715, 0xff}, | 213 | {0x715, 0xff}, |
173 | {0x716, 0x1f}, | 214 | {0x716, 0x1f}, |
174 | {0x7FE, 0x02}, | 215 | {0x7FE, 2}, |
175 | }; | 216 | }; |
176 | 217 | ||
177 | const static struct rj54n1_reg_val bank_8[] = { | 218 | const static struct rj54n1_reg_val bank_8[] = { |
@@ -359,7 +400,7 @@ const static struct rj54n1_reg_val bank_8[] = { | |||
359 | {0x8BB, 0x00}, | 400 | {0x8BB, 0x00}, |
360 | {0x8BC, 0xFF}, | 401 | {0x8BC, 0xFF}, |
361 | {0x8BD, 0x00}, | 402 | {0x8BD, 0x00}, |
362 | {0x8FE, 0x02}, | 403 | {0x8FE, 2}, |
363 | }; | 404 | }; |
364 | 405 | ||
365 | const static struct rj54n1_reg_val bank_10[] = { | 406 | const static struct rj54n1_reg_val bank_10[] = { |
@@ -440,12 +481,24 @@ static int reg_write_multiple(struct i2c_client *client, | |||
440 | return 0; | 481 | return 0; |
441 | } | 482 | } |
442 | 483 | ||
443 | static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) | 484 | static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index, |
485 | enum v4l2_mbus_pixelcode *code) | ||
444 | { | 486 | { |
445 | /* TODO: start / stop streaming */ | 487 | if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts)) |
488 | return -EINVAL; | ||
489 | |||
490 | *code = rj54n1_colour_fmts[index].code; | ||
446 | return 0; | 491 | return 0; |
447 | } | 492 | } |
448 | 493 | ||
494 | static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) | ||
495 | { | ||
496 | struct i2c_client *client = sd->priv; | ||
497 | |||
498 | /* Switch between preview and still shot modes */ | ||
499 | return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); | ||
500 | } | ||
501 | |||
449 | static int rj54n1_set_bus_param(struct soc_camera_device *icd, | 502 | static int rj54n1_set_bus_param(struct soc_camera_device *icd, |
450 | unsigned long flags) | 503 | unsigned long flags) |
451 | { | 504 | { |
@@ -502,6 +555,44 @@ static int rj54n1_commit(struct i2c_client *client) | |||
502 | return ret; | 555 | return ret; |
503 | } | 556 | } |
504 | 557 | ||
558 | static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | ||
559 | u32 *out_w, u32 *out_h); | ||
560 | |||
561 | static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
562 | { | ||
563 | struct i2c_client *client = sd->priv; | ||
564 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
565 | struct v4l2_rect *rect = &a->c; | ||
566 | unsigned int dummy, output_w, output_h, | ||
567 | input_w = rect->width, input_h = rect->height; | ||
568 | int ret; | ||
569 | |||
570 | /* arbitrary minimum width and height, edges unimportant */ | ||
571 | soc_camera_limit_side(&dummy, &input_w, | ||
572 | RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); | ||
573 | |||
574 | soc_camera_limit_side(&dummy, &input_h, | ||
575 | RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT); | ||
576 | |||
577 | output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize; | ||
578 | output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize; | ||
579 | |||
580 | dev_dbg(&client->dev, "Scaling for %ux%u : %u = %ux%u\n", | ||
581 | input_w, input_h, rj54n1->resize, output_w, output_h); | ||
582 | |||
583 | ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); | ||
584 | if (ret < 0) | ||
585 | return ret; | ||
586 | |||
587 | rj54n1->width = output_w; | ||
588 | rj54n1->height = output_h; | ||
589 | rj54n1->resize = ret; | ||
590 | rj54n1->rect.width = input_w; | ||
591 | rj54n1->rect.height = input_h; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
505 | static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 596 | static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
506 | { | 597 | { |
507 | struct i2c_client *client = sd->priv; | 598 | struct i2c_client *client = sd->priv; |
@@ -527,16 +618,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
527 | return 0; | 618 | return 0; |
528 | } | 619 | } |
529 | 620 | ||
530 | static int rj54n1_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 621 | static int rj54n1_g_fmt(struct v4l2_subdev *sd, |
622 | struct v4l2_mbus_framefmt *mf) | ||
531 | { | 623 | { |
532 | struct i2c_client *client = sd->priv; | 624 | struct i2c_client *client = sd->priv; |
533 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 625 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
534 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
535 | 626 | ||
536 | pix->pixelformat = rj54n1->fourcc; | 627 | mf->code = rj54n1->fmt->code; |
537 | pix->field = V4L2_FIELD_NONE; | 628 | mf->colorspace = rj54n1->fmt->colorspace; |
538 | pix->width = rj54n1->width; | 629 | mf->field = V4L2_FIELD_NONE; |
539 | pix->height = rj54n1->height; | 630 | mf->width = rj54n1->width; |
631 | mf->height = rj54n1->height; | ||
540 | 632 | ||
541 | return 0; | 633 | return 0; |
542 | } | 634 | } |
@@ -550,11 +642,44 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
550 | u32 *out_w, u32 *out_h) | 642 | u32 *out_w, u32 *out_h) |
551 | { | 643 | { |
552 | struct i2c_client *client = sd->priv; | 644 | struct i2c_client *client = sd->priv; |
645 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
553 | unsigned int skip, resize, input_w = *in_w, input_h = *in_h, | 646 | unsigned int skip, resize, input_w = *in_w, input_h = *in_h, |
554 | output_w = *out_w, output_h = *out_h; | 647 | output_w = *out_w, output_h = *out_h; |
555 | u16 inc_sel; | 648 | u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom; |
649 | unsigned int peak, peak_50, peak_60; | ||
556 | int ret; | 650 | int ret; |
557 | 651 | ||
652 | /* | ||
653 | * We have a problem with crops, where the window is larger than 512x384 | ||
654 | * and output window is larger than a half of the input one. In this | ||
655 | * case we have to either reduce the input window to equal or below | ||
656 | * 512x384 or the output window to equal or below 1/2 of the input. | ||
657 | */ | ||
658 | if (output_w > max(512U, input_w / 2)) { | ||
659 | if (2 * output_w > RJ54N1_MAX_WIDTH) { | ||
660 | input_w = RJ54N1_MAX_WIDTH; | ||
661 | output_w = RJ54N1_MAX_WIDTH / 2; | ||
662 | } else { | ||
663 | input_w = output_w * 2; | ||
664 | } | ||
665 | |||
666 | dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n", | ||
667 | input_w, output_w); | ||
668 | } | ||
669 | |||
670 | if (output_h > max(384U, input_h / 2)) { | ||
671 | if (2 * output_h > RJ54N1_MAX_HEIGHT) { | ||
672 | input_h = RJ54N1_MAX_HEIGHT; | ||
673 | output_h = RJ54N1_MAX_HEIGHT / 2; | ||
674 | } else { | ||
675 | input_h = output_h * 2; | ||
676 | } | ||
677 | |||
678 | dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n", | ||
679 | input_h, output_h); | ||
680 | } | ||
681 | |||
682 | /* Idea: use the read mode for snapshots, handle separate geometries */ | ||
558 | ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, | 683 | ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, |
559 | RJ54N1_Y_OUTPUT_SIZE_S_L, | 684 | RJ54N1_Y_OUTPUT_SIZE_S_L, |
560 | RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); | 685 | RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); |
@@ -566,17 +691,27 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
566 | if (ret < 0) | 691 | if (ret < 0) |
567 | return ret; | 692 | return ret; |
568 | 693 | ||
569 | if (output_w > input_w || output_h > input_h) { | 694 | if (output_w > input_w && output_h > input_h) { |
570 | input_w = output_w; | 695 | input_w = output_w; |
571 | input_h = output_h; | 696 | input_h = output_h; |
572 | 697 | ||
573 | resize = 1024; | 698 | resize = 1024; |
574 | } else { | 699 | } else { |
575 | unsigned int resize_x, resize_y; | 700 | unsigned int resize_x, resize_y; |
576 | resize_x = input_w * 1024 / output_w; | 701 | resize_x = (input_w * 1024 + output_w / 2) / output_w; |
577 | resize_y = input_h * 1024 / output_h; | 702 | resize_y = (input_h * 1024 + output_h / 2) / output_h; |
578 | 703 | ||
579 | resize = min(resize_x, resize_y); | 704 | /* We want max(resize_x, resize_y), check if it still fits */ |
705 | if (resize_x > resize_y && | ||
706 | (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT) | ||
707 | resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) / | ||
708 | output_h; | ||
709 | else if (resize_y > resize_x && | ||
710 | (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH) | ||
711 | resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) / | ||
712 | output_w; | ||
713 | else | ||
714 | resize = max(resize_x, resize_y); | ||
580 | 715 | ||
581 | /* Prohibited value ranges */ | 716 | /* Prohibited value ranges */ |
582 | switch (resize) { | 717 | switch (resize) { |
@@ -589,12 +724,9 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
589 | case 8160 ... 8191: | 724 | case 8160 ... 8191: |
590 | resize = 8159; | 725 | resize = 8159; |
591 | break; | 726 | break; |
592 | case 16320 ... 16383: | 727 | case 16320 ... 16384: |
593 | resize = 16319; | 728 | resize = 16319; |
594 | } | 729 | } |
595 | |||
596 | input_w = output_w * resize / 1024; | ||
597 | input_h = output_h * resize / 1024; | ||
598 | } | 730 | } |
599 | 731 | ||
600 | /* Set scaling */ | 732 | /* Set scaling */ |
@@ -607,9 +739,18 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
607 | 739 | ||
608 | /* | 740 | /* |
609 | * Configure a skipping bitmask. The sensor will select a skipping value | 741 | * Configure a skipping bitmask. The sensor will select a skipping value |
610 | * among set bits automatically. | 742 | * among set bits automatically. This is very unclear in the datasheet |
743 | * too. I was told, in this register one enables all skipping values, | ||
744 | * that are required for a specific resize, and the camera selects | ||
745 | * automatically, which ones to use. But it is unclear how to identify, | ||
746 | * which cropping values are needed. Secondly, why don't we just set all | ||
747 | * bits and let the camera choose? Would it increase processing time and | ||
748 | * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to | ||
749 | * improve the image quality or stability for larger frames (see comment | ||
750 | * above), but I didn't check the framerate. | ||
611 | */ | 751 | */ |
612 | skip = min(resize / 1024, (unsigned)15); | 752 | skip = min(resize / 1024, (unsigned)15); |
753 | |||
613 | inc_sel = 1 << skip; | 754 | inc_sel = 1 << skip; |
614 | 755 | ||
615 | if (inc_sel <= 2) | 756 | if (inc_sel <= 2) |
@@ -621,6 +762,43 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
621 | if (!ret) | 762 | if (!ret) |
622 | ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); | 763 | ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); |
623 | 764 | ||
765 | if (!rj54n1->auto_wb) { | ||
766 | /* Auto white balance window */ | ||
767 | wb_left = output_w / 16; | ||
768 | wb_right = (3 * output_w / 4 - 3) / 4; | ||
769 | wb_top = output_h / 16; | ||
770 | wb_bottom = (3 * output_h / 4 - 3) / 4; | ||
771 | wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) | | ||
772 | ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1); | ||
773 | |||
774 | if (!ret) | ||
775 | ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8); | ||
776 | if (!ret) | ||
777 | ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left); | ||
778 | if (!ret) | ||
779 | ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top); | ||
780 | if (!ret) | ||
781 | ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right); | ||
782 | if (!ret) | ||
783 | ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom); | ||
784 | } | ||
785 | |||
786 | /* Antiflicker */ | ||
787 | peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz / | ||
788 | 10000; | ||
789 | peak_50 = peak / 6; | ||
790 | peak_60 = peak / 5; | ||
791 | |||
792 | if (!ret) | ||
793 | ret = reg_write(client, RJ54N1_PEAK_H, | ||
794 | ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8)); | ||
795 | if (!ret) | ||
796 | ret = reg_write(client, RJ54N1_PEAK_50, peak_50); | ||
797 | if (!ret) | ||
798 | ret = reg_write(client, RJ54N1_PEAK_60, peak_60); | ||
799 | if (!ret) | ||
800 | ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150); | ||
801 | |||
624 | /* Start resizing */ | 802 | /* Start resizing */ |
625 | if (!ret) | 803 | if (!ret) |
626 | ret = reg_write(client, RJ54N1_RESIZE_CONTROL, | 804 | ret = reg_write(client, RJ54N1_RESIZE_CONTROL, |
@@ -629,8 +807,6 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
629 | if (ret < 0) | 807 | if (ret < 0) |
630 | return ret; | 808 | return ret; |
631 | 809 | ||
632 | dev_dbg(&client->dev, "resize %u, skip %u\n", resize, skip); | ||
633 | |||
634 | /* Constant taken from manufacturer's example */ | 810 | /* Constant taken from manufacturer's example */ |
635 | msleep(230); | 811 | msleep(230); |
636 | 812 | ||
@@ -638,11 +814,14 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, | |||
638 | if (ret < 0) | 814 | if (ret < 0) |
639 | return ret; | 815 | return ret; |
640 | 816 | ||
641 | *in_w = input_w; | 817 | *in_w = (output_w * resize + 512) / 1024; |
642 | *in_h = input_h; | 818 | *in_h = (output_h * resize + 512) / 1024; |
643 | *out_w = output_w; | 819 | *out_w = output_w; |
644 | *out_h = output_h; | 820 | *out_h = output_h; |
645 | 821 | ||
822 | dev_dbg(&client->dev, "Scaled for %ux%u : %u = %ux%u, skip %u\n", | ||
823 | *in_w, *in_h, resize, output_w, output_h, skip); | ||
824 | |||
646 | return resize; | 825 | return resize; |
647 | } | 826 | } |
648 | 827 | ||
@@ -653,14 +832,14 @@ static int rj54n1_set_clock(struct i2c_client *client) | |||
653 | 832 | ||
654 | /* Enable external clock */ | 833 | /* Enable external clock */ |
655 | ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); | 834 | ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); |
656 | /* Leave stand-by */ | 835 | /* Leave stand-by. Note: use this when implementing suspend / resume */ |
657 | if (!ret) | 836 | if (!ret) |
658 | ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); | 837 | ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); |
659 | 838 | ||
660 | if (!ret) | 839 | if (!ret) |
661 | ret = reg_write(client, RJ54N1_PLL_L, 2); | 840 | ret = reg_write(client, RJ54N1_PLL_L, PLL_L); |
662 | if (!ret) | 841 | if (!ret) |
663 | ret = reg_write(client, RJ54N1_PLL_N, 0x31); | 842 | ret = reg_write(client, RJ54N1_PLL_N, PLL_N); |
664 | 843 | ||
665 | /* TGCLK dividers */ | 844 | /* TGCLK dividers */ |
666 | if (!ret) | 845 | if (!ret) |
@@ -719,6 +898,7 @@ static int rj54n1_set_clock(struct i2c_client *client) | |||
719 | "Resetting RJ54N1CB0C clock failed: %d!\n", ret); | 898 | "Resetting RJ54N1CB0C clock failed: %d!\n", ret); |
720 | return -EIO; | 899 | return -EIO; |
721 | } | 900 | } |
901 | |||
722 | /* Start the PLL */ | 902 | /* Start the PLL */ |
723 | ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); | 903 | ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); |
724 | 904 | ||
@@ -731,6 +911,7 @@ static int rj54n1_set_clock(struct i2c_client *client) | |||
731 | 911 | ||
732 | static int rj54n1_reg_init(struct i2c_client *client) | 912 | static int rj54n1_reg_init(struct i2c_client *client) |
733 | { | 913 | { |
914 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
734 | int ret = rj54n1_set_clock(client); | 915 | int ret = rj54n1_set_clock(client); |
735 | 916 | ||
736 | if (!ret) | 917 | if (!ret) |
@@ -753,14 +934,26 @@ static int rj54n1_reg_init(struct i2c_client *client) | |||
753 | if (!ret) | 934 | if (!ret) |
754 | ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); | 935 | ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); |
755 | 936 | ||
756 | /* Mirror the image back: default is upside down and left-to-right... */ | 937 | /* |
938 | * Mirror the image back: default is upside down and left-to-right... | ||
939 | * Set manual preview / still shot switching | ||
940 | */ | ||
757 | if (!ret) | 941 | if (!ret) |
758 | ret = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 3, 3); | 942 | ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27); |
759 | 943 | ||
760 | if (!ret) | 944 | if (!ret) |
761 | ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); | 945 | ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); |
946 | |||
947 | /* Auto exposure area */ | ||
762 | if (!ret) | 948 | if (!ret) |
949 | ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80); | ||
950 | /* Check current auto WB config */ | ||
951 | if (!ret) | ||
952 | ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I); | ||
953 | if (ret >= 0) { | ||
954 | rj54n1->auto_wb = ret & 0x80; | ||
763 | ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); | 955 | ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); |
956 | } | ||
764 | if (!ret) | 957 | if (!ret) |
765 | ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); | 958 | ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); |
766 | 959 | ||
@@ -777,8 +970,9 @@ static int rj54n1_reg_init(struct i2c_client *client) | |||
777 | ret = reg_write(client, RJ54N1_RESET_STANDBY, | 970 | ret = reg_write(client, RJ54N1_RESET_STANDBY, |
778 | E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); | 971 | E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); |
779 | 972 | ||
973 | /* Start register update? Same register as 0x?FE in many bank_* sets */ | ||
780 | if (!ret) | 974 | if (!ret) |
781 | ret = reg_write(client, 0x7fe, 2); | 975 | ret = reg_write(client, RJ54N1_FWFLG, 2); |
782 | 976 | ||
783 | /* Constant taken from manufacturer's example */ | 977 | /* Constant taken from manufacturer's example */ |
784 | msleep(700); | 978 | msleep(700); |
@@ -786,27 +980,44 @@ static int rj54n1_reg_init(struct i2c_client *client) | |||
786 | return ret; | 980 | return ret; |
787 | } | 981 | } |
788 | 982 | ||
789 | /* FIXME: streaming output only up to 800x600 is functional */ | 983 | static int rj54n1_try_fmt(struct v4l2_subdev *sd, |
790 | static int rj54n1_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 984 | struct v4l2_mbus_framefmt *mf) |
791 | { | 985 | { |
792 | struct v4l2_pix_format *pix = &f->fmt.pix; | 986 | struct i2c_client *client = sd->priv; |
987 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
988 | const struct rj54n1_datafmt *fmt; | ||
989 | int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 || | ||
990 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE || | ||
991 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE || | ||
992 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE || | ||
993 | mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE; | ||
994 | |||
995 | dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", | ||
996 | __func__, mf->code, mf->width, mf->height); | ||
997 | |||
998 | fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, | ||
999 | ARRAY_SIZE(rj54n1_colour_fmts)); | ||
1000 | if (!fmt) { | ||
1001 | fmt = rj54n1->fmt; | ||
1002 | mf->code = fmt->code; | ||
1003 | } | ||
793 | 1004 | ||
794 | pix->field = V4L2_FIELD_NONE; | 1005 | mf->field = V4L2_FIELD_NONE; |
1006 | mf->colorspace = fmt->colorspace; | ||
795 | 1007 | ||
796 | if (pix->width > 800) | 1008 | v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, |
797 | pix->width = 800; | 1009 | &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); |
798 | if (pix->height > 600) | ||
799 | pix->height = 600; | ||
800 | 1010 | ||
801 | return 0; | 1011 | return 0; |
802 | } | 1012 | } |
803 | 1013 | ||
804 | static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 1014 | static int rj54n1_s_fmt(struct v4l2_subdev *sd, |
1015 | struct v4l2_mbus_framefmt *mf) | ||
805 | { | 1016 | { |
806 | struct i2c_client *client = sd->priv; | 1017 | struct i2c_client *client = sd->priv; |
807 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 1018 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
808 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1019 | const struct rj54n1_datafmt *fmt; |
809 | unsigned int output_w, output_h, | 1020 | unsigned int output_w, output_h, max_w, max_h, |
810 | input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; | 1021 | input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; |
811 | int ret; | 1022 | int ret; |
812 | 1023 | ||
@@ -814,14 +1025,13 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
814 | * The host driver can call us without .try_fmt(), so, we have to take | 1025 | * The host driver can call us without .try_fmt(), so, we have to take |
815 | * care ourseleves | 1026 | * care ourseleves |
816 | */ | 1027 | */ |
817 | ret = rj54n1_try_fmt(sd, f); | 1028 | rj54n1_try_fmt(sd, mf); |
818 | 1029 | ||
819 | /* | 1030 | /* |
820 | * Verify if the sensor has just been powered on. TODO: replace this | 1031 | * Verify if the sensor has just been powered on. TODO: replace this |
821 | * with proper PM, when a suitable API is available. | 1032 | * with proper PM, when a suitable API is available. |
822 | */ | 1033 | */ |
823 | if (!ret) | 1034 | ret = reg_read(client, RJ54N1_RESET_STANDBY); |
824 | ret = reg_read(client, RJ54N1_RESET_STANDBY); | ||
825 | if (ret < 0) | 1035 | if (ret < 0) |
826 | return ret; | 1036 | return ret; |
827 | 1037 | ||
@@ -831,50 +1041,105 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
831 | return ret; | 1041 | return ret; |
832 | } | 1042 | } |
833 | 1043 | ||
1044 | dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", | ||
1045 | __func__, mf->code, mf->width, mf->height); | ||
1046 | |||
834 | /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ | 1047 | /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ |
835 | switch (pix->pixelformat) { | 1048 | switch (mf->code) { |
836 | case V4L2_PIX_FMT_YUYV: | 1049 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
837 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); | 1050 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); |
838 | if (!ret) | 1051 | if (!ret) |
839 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | 1052 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); |
840 | break; | 1053 | break; |
841 | case V4L2_PIX_FMT_RGB565: | 1054 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
1055 | ret = reg_write(client, RJ54N1_OUT_SEL, 0); | ||
1056 | if (!ret) | ||
1057 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
1058 | break; | ||
1059 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
1060 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); | ||
1061 | if (!ret) | ||
1062 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | ||
1063 | break; | ||
1064 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
842 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); | 1065 | ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); |
843 | if (!ret) | 1066 | if (!ret) |
1067 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
1068 | break; | ||
1069 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: | ||
1070 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
1071 | if (!ret) | ||
844 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | 1072 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); |
1073 | if (!ret) | ||
1074 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); | ||
1075 | break; | ||
1076 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: | ||
1077 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
1078 | if (!ret) | ||
1079 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); | ||
1080 | if (!ret) | ||
1081 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); | ||
1082 | break; | ||
1083 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: | ||
1084 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
1085 | if (!ret) | ||
1086 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
1087 | if (!ret) | ||
1088 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); | ||
1089 | break; | ||
1090 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: | ||
1091 | ret = reg_write(client, RJ54N1_OUT_SEL, 4); | ||
1092 | if (!ret) | ||
1093 | ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); | ||
1094 | if (!ret) | ||
1095 | ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); | ||
1096 | break; | ||
1097 | case V4L2_MBUS_FMT_SBGGR10_1X10: | ||
1098 | ret = reg_write(client, RJ54N1_OUT_SEL, 5); | ||
845 | break; | 1099 | break; |
846 | default: | 1100 | default: |
847 | ret = -EINVAL; | 1101 | ret = -EINVAL; |
848 | } | 1102 | } |
849 | 1103 | ||
1104 | /* Special case: a raw mode with 10 bits of data per clock tick */ | ||
1105 | if (!ret) | ||
1106 | ret = reg_set(client, RJ54N1_OCLK_SEL_EN, | ||
1107 | (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2); | ||
1108 | |||
850 | if (ret < 0) | 1109 | if (ret < 0) |
851 | return ret; | 1110 | return ret; |
852 | 1111 | ||
853 | /* Supported scales 1:1 - 1:16 */ | 1112 | /* Supported scales 1:1 >= scale > 1:16 */ |
854 | if (pix->width < input_w / 16) | 1113 | max_w = mf->width * (16 * 1024 - 1) / 1024; |
855 | pix->width = input_w / 16; | 1114 | if (input_w > max_w) |
856 | if (pix->height < input_h / 16) | 1115 | input_w = max_w; |
857 | pix->height = input_h / 16; | 1116 | max_h = mf->height * (16 * 1024 - 1) / 1024; |
1117 | if (input_h > max_h) | ||
1118 | input_h = max_h; | ||
858 | 1119 | ||
859 | output_w = pix->width; | 1120 | output_w = mf->width; |
860 | output_h = pix->height; | 1121 | output_h = mf->height; |
861 | 1122 | ||
862 | ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); | 1123 | ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); |
863 | if (ret < 0) | 1124 | if (ret < 0) |
864 | return ret; | 1125 | return ret; |
865 | 1126 | ||
866 | rj54n1->fourcc = pix->pixelformat; | 1127 | fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, |
1128 | ARRAY_SIZE(rj54n1_colour_fmts)); | ||
1129 | |||
1130 | rj54n1->fmt = fmt; | ||
867 | rj54n1->resize = ret; | 1131 | rj54n1->resize = ret; |
868 | rj54n1->rect.width = input_w; | 1132 | rj54n1->rect.width = input_w; |
869 | rj54n1->rect.height = input_h; | 1133 | rj54n1->rect.height = input_h; |
870 | rj54n1->width = output_w; | 1134 | rj54n1->width = output_w; |
871 | rj54n1->height = output_h; | 1135 | rj54n1->height = output_h; |
872 | 1136 | ||
873 | pix->width = output_w; | 1137 | mf->width = output_w; |
874 | pix->height = output_h; | 1138 | mf->height = output_h; |
875 | pix->field = V4L2_FIELD_NONE; | 1139 | mf->field = V4L2_FIELD_NONE; |
1140 | mf->colorspace = fmt->colorspace; | ||
876 | 1141 | ||
877 | return ret; | 1142 | return 0; |
878 | } | 1143 | } |
879 | 1144 | ||
880 | static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, | 1145 | static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, |
@@ -963,6 +1228,14 @@ static const struct v4l2_queryctrl rj54n1_controls[] = { | |||
963 | .step = 1, | 1228 | .step = 1, |
964 | .default_value = 66, | 1229 | .default_value = 66, |
965 | .flags = V4L2_CTRL_FLAG_SLIDER, | 1230 | .flags = V4L2_CTRL_FLAG_SLIDER, |
1231 | }, { | ||
1232 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
1233 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1234 | .name = "Auto white balance", | ||
1235 | .minimum = 0, | ||
1236 | .maximum = 1, | ||
1237 | .step = 1, | ||
1238 | .default_value = 1, | ||
966 | }, | 1239 | }, |
967 | }; | 1240 | }; |
968 | 1241 | ||
@@ -976,6 +1249,7 @@ static struct soc_camera_ops rj54n1_ops = { | |||
976 | static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 1249 | static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
977 | { | 1250 | { |
978 | struct i2c_client *client = sd->priv; | 1251 | struct i2c_client *client = sd->priv; |
1252 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
979 | int data; | 1253 | int data; |
980 | 1254 | ||
981 | switch (ctrl->id) { | 1255 | switch (ctrl->id) { |
@@ -998,6 +1272,9 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
998 | 1272 | ||
999 | ctrl->value = data / 2; | 1273 | ctrl->value = data / 2; |
1000 | break; | 1274 | break; |
1275 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1276 | ctrl->value = rj54n1->auto_wb; | ||
1277 | break; | ||
1001 | } | 1278 | } |
1002 | 1279 | ||
1003 | return 0; | 1280 | return 0; |
@@ -1007,6 +1284,7 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
1007 | { | 1284 | { |
1008 | int data; | 1285 | int data; |
1009 | struct i2c_client *client = sd->priv; | 1286 | struct i2c_client *client = sd->priv; |
1287 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
1010 | const struct v4l2_queryctrl *qctrl; | 1288 | const struct v4l2_queryctrl *qctrl; |
1011 | 1289 | ||
1012 | qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); | 1290 | qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); |
@@ -1037,6 +1315,13 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
1037 | else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) | 1315 | else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) |
1038 | return -EIO; | 1316 | return -EIO; |
1039 | break; | 1317 | break; |
1318 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1319 | /* Auto WB area - whole image */ | ||
1320 | if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, | ||
1321 | 0x80) < 0) | ||
1322 | return -EIO; | ||
1323 | rj54n1->auto_wb = ctrl->value; | ||
1324 | break; | ||
1040 | } | 1325 | } |
1041 | 1326 | ||
1042 | return 0; | 1327 | return 0; |
@@ -1054,10 +1339,12 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | |||
1054 | 1339 | ||
1055 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1340 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
1056 | .s_stream = rj54n1_s_stream, | 1341 | .s_stream = rj54n1_s_stream, |
1057 | .s_fmt = rj54n1_s_fmt, | 1342 | .s_mbus_fmt = rj54n1_s_fmt, |
1058 | .g_fmt = rj54n1_g_fmt, | 1343 | .g_mbus_fmt = rj54n1_g_fmt, |
1059 | .try_fmt = rj54n1_try_fmt, | 1344 | .try_mbus_fmt = rj54n1_try_fmt, |
1345 | .enum_mbus_fmt = rj54n1_enum_fmt, | ||
1060 | .g_crop = rj54n1_g_crop, | 1346 | .g_crop = rj54n1_g_crop, |
1347 | .s_crop = rj54n1_s_crop, | ||
1061 | .cropcap = rj54n1_cropcap, | 1348 | .cropcap = rj54n1_cropcap, |
1062 | }; | 1349 | }; |
1063 | 1350 | ||
@@ -1066,21 +1353,13 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { | |||
1066 | .video = &rj54n1_subdev_video_ops, | 1353 | .video = &rj54n1_subdev_video_ops, |
1067 | }; | 1354 | }; |
1068 | 1355 | ||
1069 | static int rj54n1_pin_config(struct i2c_client *client) | ||
1070 | { | ||
1071 | /* | ||
1072 | * Experimentally found out IOCTRL wired to 0. TODO: add to platform | ||
1073 | * data: 0 or 1 << 7. | ||
1074 | */ | ||
1075 | return reg_write(client, RJ54N1_IOC, 0); | ||
1076 | } | ||
1077 | |||
1078 | /* | 1356 | /* |
1079 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 1357 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
1080 | * this wasn't our capture interface, so, we wait for the right one | 1358 | * this wasn't our capture interface, so, we wait for the right one |
1081 | */ | 1359 | */ |
1082 | static int rj54n1_video_probe(struct soc_camera_device *icd, | 1360 | static int rj54n1_video_probe(struct soc_camera_device *icd, |
1083 | struct i2c_client *client) | 1361 | struct i2c_client *client, |
1362 | struct rj54n1_pdata *priv) | ||
1084 | { | 1363 | { |
1085 | int data1, data2; | 1364 | int data1, data2; |
1086 | int ret; | 1365 | int ret; |
@@ -1101,7 +1380,8 @@ static int rj54n1_video_probe(struct soc_camera_device *icd, | |||
1101 | goto ei2c; | 1380 | goto ei2c; |
1102 | } | 1381 | } |
1103 | 1382 | ||
1104 | ret = rj54n1_pin_config(client); | 1383 | /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */ |
1384 | ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7); | ||
1105 | if (ret < 0) | 1385 | if (ret < 0) |
1106 | goto ei2c; | 1386 | goto ei2c; |
1107 | 1387 | ||
@@ -1119,6 +1399,7 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1119 | struct soc_camera_device *icd = client->dev.platform_data; | 1399 | struct soc_camera_device *icd = client->dev.platform_data; |
1120 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1400 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1121 | struct soc_camera_link *icl; | 1401 | struct soc_camera_link *icl; |
1402 | struct rj54n1_pdata *rj54n1_priv; | ||
1122 | int ret; | 1403 | int ret; |
1123 | 1404 | ||
1124 | if (!icd) { | 1405 | if (!icd) { |
@@ -1127,11 +1408,13 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1127 | } | 1408 | } |
1128 | 1409 | ||
1129 | icl = to_soc_camera_link(icd); | 1410 | icl = to_soc_camera_link(icd); |
1130 | if (!icl) { | 1411 | if (!icl || !icl->priv) { |
1131 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); | 1412 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); |
1132 | return -EINVAL; | 1413 | return -EINVAL; |
1133 | } | 1414 | } |
1134 | 1415 | ||
1416 | rj54n1_priv = icl->priv; | ||
1417 | |||
1135 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1418 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1136 | dev_warn(&adapter->dev, | 1419 | dev_warn(&adapter->dev, |
1137 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); | 1420 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); |
@@ -1153,10 +1436,12 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1153 | rj54n1->rect.height = RJ54N1_MAX_HEIGHT; | 1436 | rj54n1->rect.height = RJ54N1_MAX_HEIGHT; |
1154 | rj54n1->width = RJ54N1_MAX_WIDTH; | 1437 | rj54n1->width = RJ54N1_MAX_WIDTH; |
1155 | rj54n1->height = RJ54N1_MAX_HEIGHT; | 1438 | rj54n1->height = RJ54N1_MAX_HEIGHT; |
1156 | rj54n1->fourcc = V4L2_PIX_FMT_YUYV; | 1439 | rj54n1->fmt = &rj54n1_colour_fmts[0]; |
1157 | rj54n1->resize = 1024; | 1440 | rj54n1->resize = 1024; |
1441 | rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / | ||
1442 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); | ||
1158 | 1443 | ||
1159 | ret = rj54n1_video_probe(icd, client); | 1444 | ret = rj54n1_video_probe(icd, client, rj54n1_priv); |
1160 | if (ret < 0) { | 1445 | if (ret < 0) { |
1161 | icd->ops = NULL; | 1446 | icd->ops = NULL; |
1162 | i2c_set_clientdata(client, NULL); | 1447 | i2c_set_clientdata(client, NULL); |
@@ -1164,9 +1449,6 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1164 | return ret; | 1449 | return ret; |
1165 | } | 1450 | } |
1166 | 1451 | ||
1167 | icd->formats = rj54n1_colour_formats; | ||
1168 | icd->num_formats = ARRAY_SIZE(rj54n1_colour_formats); | ||
1169 | |||
1170 | return ret; | 1452 | return ret; |
1171 | } | 1453 | } |
1172 | 1454 | ||
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 41765f3c7c28..fb742f1ae711 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c | |||
@@ -233,7 +233,6 @@ struct s2255_dev { | |||
233 | 233 | ||
234 | struct s2255_dmaqueue vidq[MAX_CHANNELS]; | 234 | struct s2255_dmaqueue vidq[MAX_CHANNELS]; |
235 | struct video_device *vdev[MAX_CHANNELS]; | 235 | struct video_device *vdev[MAX_CHANNELS]; |
236 | struct list_head s2255_devlist; | ||
237 | struct timer_list timer; | 236 | struct timer_list timer; |
238 | struct s2255_fw *fw_data; | 237 | struct s2255_fw *fw_data; |
239 | struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; | 238 | struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; |
@@ -313,8 +312,6 @@ struct s2255_fh { | |||
313 | /* Channels on box are in reverse order */ | 312 | /* Channels on box are in reverse order */ |
314 | static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; | 313 | static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; |
315 | 314 | ||
316 | static LIST_HEAD(s2255_devlist); | ||
317 | |||
318 | static int debug; | 315 | static int debug; |
319 | static int *s2255_debug = &debug; | 316 | static int *s2255_debug = &debug; |
320 | 317 | ||
@@ -1533,32 +1530,24 @@ static int vidioc_s_parm(struct file *file, void *priv, | |||
1533 | } | 1530 | } |
1534 | static int s2255_open(struct file *file) | 1531 | static int s2255_open(struct file *file) |
1535 | { | 1532 | { |
1536 | int minor = video_devdata(file)->minor; | 1533 | struct video_device *vdev = video_devdata(file); |
1537 | struct s2255_dev *h, *dev = NULL; | 1534 | struct s2255_dev *dev = video_drvdata(file); |
1538 | struct s2255_fh *fh; | 1535 | struct s2255_fh *fh; |
1539 | struct list_head *list; | 1536 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1540 | enum v4l2_buf_type type = 0; | ||
1541 | int i = 0; | 1537 | int i = 0; |
1542 | int cur_channel = -1; | 1538 | int cur_channel = -1; |
1543 | int state; | 1539 | int state; |
1544 | dprintk(1, "s2255: open called (minor=%d)\n", minor); | 1540 | |
1541 | dprintk(1, "s2255: open called (dev=%s)\n", | ||
1542 | video_device_node_name(vdev)); | ||
1545 | 1543 | ||
1546 | lock_kernel(); | 1544 | lock_kernel(); |
1547 | list_for_each(list, &s2255_devlist) { | ||
1548 | h = list_entry(list, struct s2255_dev, s2255_devlist); | ||
1549 | for (i = 0; i < MAX_CHANNELS; i++) { | ||
1550 | if (h->vdev[i]->minor == minor) { | ||
1551 | cur_channel = i; | ||
1552 | dev = h; | ||
1553 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1554 | } | ||
1555 | } | ||
1556 | } | ||
1557 | 1545 | ||
1558 | if ((NULL == dev) || (cur_channel == -1)) { | 1546 | for (i = 0; i < MAX_CHANNELS; i++) { |
1559 | unlock_kernel(); | 1547 | if (dev->vdev[i] == vdev) { |
1560 | printk(KERN_INFO "s2255: openv4l no dev\n"); | 1548 | cur_channel = i; |
1561 | return -ENODEV; | 1549 | break; |
1550 | } | ||
1562 | } | 1551 | } |
1563 | 1552 | ||
1564 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) { | 1553 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) { |
@@ -1662,8 +1651,9 @@ static int s2255_open(struct file *file) | |||
1662 | for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) | 1651 | for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) |
1663 | qctl_regs[i] = s2255_qctrl[i].default_value; | 1652 | qctl_regs[i] = s2255_qctrl[i].default_value; |
1664 | 1653 | ||
1665 | dprintk(1, "s2255drv: open minor=%d type=%s users=%d\n", | 1654 | dprintk(1, "s2255drv: open dev=%s type=%s users=%d\n", |
1666 | minor, v4l2_type_names[type], dev->users[cur_channel]); | 1655 | video_device_node_name(vdev), v4l2_type_names[type], |
1656 | dev->users[cur_channel]); | ||
1667 | dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", | 1657 | dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", |
1668 | (unsigned long)fh, (unsigned long)dev, | 1658 | (unsigned long)fh, (unsigned long)dev, |
1669 | (unsigned long)&dev->vidq[cur_channel]); | 1659 | (unsigned long)&dev->vidq[cur_channel]); |
@@ -1699,7 +1689,6 @@ static unsigned int s2255_poll(struct file *file, | |||
1699 | static void s2255_destroy(struct kref *kref) | 1689 | static void s2255_destroy(struct kref *kref) |
1700 | { | 1690 | { |
1701 | struct s2255_dev *dev = to_s2255_dev(kref); | 1691 | struct s2255_dev *dev = to_s2255_dev(kref); |
1702 | struct list_head *list; | ||
1703 | int i; | 1692 | int i; |
1704 | if (!dev) { | 1693 | if (!dev) { |
1705 | printk(KERN_ERR "s2255drv: kref problem\n"); | 1694 | printk(KERN_ERR "s2255drv: kref problem\n"); |
@@ -1733,10 +1722,6 @@ static void s2255_destroy(struct kref *kref) | |||
1733 | usb_put_dev(dev->udev); | 1722 | usb_put_dev(dev->udev); |
1734 | dprintk(1, "%s", __func__); | 1723 | dprintk(1, "%s", __func__); |
1735 | 1724 | ||
1736 | while (!list_empty(&s2255_devlist)) { | ||
1737 | list = s2255_devlist.next; | ||
1738 | list_del(list); | ||
1739 | } | ||
1740 | mutex_unlock(&dev->open_lock); | 1725 | mutex_unlock(&dev->open_lock); |
1741 | kfree(dev); | 1726 | kfree(dev); |
1742 | } | 1727 | } |
@@ -1745,7 +1730,8 @@ static int s2255_close(struct file *file) | |||
1745 | { | 1730 | { |
1746 | struct s2255_fh *fh = file->private_data; | 1731 | struct s2255_fh *fh = file->private_data; |
1747 | struct s2255_dev *dev = fh->dev; | 1732 | struct s2255_dev *dev = fh->dev; |
1748 | int minor = video_devdata(file)->minor; | 1733 | struct video_device *vdev = video_devdata(file); |
1734 | |||
1749 | if (!dev) | 1735 | if (!dev) |
1750 | return -ENODEV; | 1736 | return -ENODEV; |
1751 | 1737 | ||
@@ -1765,8 +1751,8 @@ static int s2255_close(struct file *file) | |||
1765 | mutex_unlock(&dev->open_lock); | 1751 | mutex_unlock(&dev->open_lock); |
1766 | 1752 | ||
1767 | kref_put(&dev->kref, s2255_destroy); | 1753 | kref_put(&dev->kref, s2255_destroy); |
1768 | dprintk(1, "s2255: close called (minor=%d, users=%d)\n", | 1754 | dprintk(1, "s2255: close called (dev=%s, users=%d)\n", |
1769 | minor, dev->users[fh->channel]); | 1755 | video_device_node_name(vdev), dev->users[fh->channel]); |
1770 | kfree(fh); | 1756 | kfree(fh); |
1771 | return 0; | 1757 | return 0; |
1772 | } | 1758 | } |
@@ -1830,7 +1816,6 @@ static struct video_device template = { | |||
1830 | .name = "s2255v", | 1816 | .name = "s2255v", |
1831 | .fops = &s2255_fops_v4l, | 1817 | .fops = &s2255_fops_v4l, |
1832 | .ioctl_ops = &s2255_ioctl_ops, | 1818 | .ioctl_ops = &s2255_ioctl_ops, |
1833 | .minor = -1, | ||
1834 | .release = video_device_release, | 1819 | .release = video_device_release, |
1835 | .tvnorms = S2255_NORMS, | 1820 | .tvnorms = S2255_NORMS, |
1836 | .current_norm = V4L2_STD_NTSC_M, | 1821 | .current_norm = V4L2_STD_NTSC_M, |
@@ -1843,7 +1828,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) | |||
1843 | int cur_nr = video_nr; | 1828 | int cur_nr = video_nr; |
1844 | 1829 | ||
1845 | /* initialize all video 4 linux */ | 1830 | /* initialize all video 4 linux */ |
1846 | list_add_tail(&dev->s2255_devlist, &s2255_devlist); | ||
1847 | /* register 4 video devices */ | 1831 | /* register 4 video devices */ |
1848 | for (i = 0; i < MAX_CHANNELS; i++) { | 1832 | for (i = 0; i < MAX_CHANNELS; i++) { |
1849 | INIT_LIST_HEAD(&dev->vidq[i].active); | 1833 | INIT_LIST_HEAD(&dev->vidq[i].active); |
@@ -1853,6 +1837,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) | |||
1853 | dev->vdev[i] = video_device_alloc(); | 1837 | dev->vdev[i] = video_device_alloc(); |
1854 | memcpy(dev->vdev[i], &template, sizeof(struct video_device)); | 1838 | memcpy(dev->vdev[i], &template, sizeof(struct video_device)); |
1855 | dev->vdev[i]->parent = &dev->interface->dev; | 1839 | dev->vdev[i]->parent = &dev->interface->dev; |
1840 | video_set_drvdata(dev->vdev[i], dev); | ||
1856 | if (video_nr == -1) | 1841 | if (video_nr == -1) |
1857 | ret = video_register_device(dev->vdev[i], | 1842 | ret = video_register_device(dev->vdev[i], |
1858 | VFL_TYPE_GRABBER, | 1843 | VFL_TYPE_GRABBER, |
@@ -1880,7 +1865,7 @@ static void s2255_exit_v4l(struct s2255_dev *dev) | |||
1880 | 1865 | ||
1881 | int i; | 1866 | int i; |
1882 | for (i = 0; i < MAX_CHANNELS; i++) { | 1867 | for (i = 0; i < MAX_CHANNELS; i++) { |
1883 | if (-1 != dev->vdev[i]->minor) { | 1868 | if (video_is_registered(dev->vdev[i])) { |
1884 | video_unregister_device(dev->vdev[i]); | 1869 | video_unregister_device(dev->vdev[i]); |
1885 | printk(KERN_INFO "s2255 unregistered\n"); | 1870 | printk(KERN_INFO "s2255 unregistered\n"); |
1886 | } else { | 1871 | } else { |
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index b624a4c01fdc..5ab6a0f901c0 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c | |||
@@ -1036,7 +1036,6 @@ static struct video_device saa_template = | |||
1036 | .name = "saa5246a", | 1036 | .name = "saa5246a", |
1037 | .fops = &saa_fops, | 1037 | .fops = &saa_fops, |
1038 | .release = video_device_release, | 1038 | .release = video_device_release, |
1039 | .minor = -1, | ||
1040 | }; | 1039 | }; |
1041 | 1040 | ||
1042 | static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 1041 | static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 7e40d6d99dd0..03f572708b85 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -7211,9 +7211,31 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
7211 | } | 7211 | } |
7212 | case SAA7134_BOARD_FLYDVB_TRIO: | 7212 | case SAA7134_BOARD_FLYDVB_TRIO: |
7213 | { | 7213 | { |
7214 | u8 temp = 0; | ||
7215 | int rc; | ||
7214 | u8 data[] = { 0x3c, 0x33, 0x62}; | 7216 | u8 data[] = { 0x3c, 0x33, 0x62}; |
7215 | struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; | 7217 | struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; |
7216 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 7218 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
7219 | |||
7220 | /* | ||
7221 | * send weak up message to pic16C505 chip | ||
7222 | * @ LifeView FlyDVB Trio | ||
7223 | */ | ||
7224 | msg.buf = &temp; | ||
7225 | msg.addr = 0x0b; | ||
7226 | msg.len = 1; | ||
7227 | if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) { | ||
7228 | printk(KERN_WARNING "%s: send wake up byte to pic16C505" | ||
7229 | "(IR chip) failed\n", dev->name); | ||
7230 | } else { | ||
7231 | msg.flags = I2C_M_RD; | ||
7232 | rc = i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
7233 | printk(KERN_INFO "%s: probe IR chip @ i2c 0x%02x: %s\n", | ||
7234 | dev->name, msg.addr, | ||
7235 | (1 == rc) ? "yes" : "no"); | ||
7236 | if (rc == 1) | ||
7237 | dev->has_remote = SAA7134_REMOTE_I2C; | ||
7238 | } | ||
7217 | break; | 7239 | break; |
7218 | } | 7240 | } |
7219 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 7241 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 0ba7f5af0fc3..9f85e917f9f3 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -797,27 +797,28 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, | |||
797 | vfd->debug = video_debug; | 797 | vfd->debug = video_debug; |
798 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | 798 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", |
799 | dev->name, type, saa7134_boards[dev->board].name); | 799 | dev->name, type, saa7134_boards[dev->board].name); |
800 | video_set_drvdata(vfd, dev); | ||
800 | return vfd; | 801 | return vfd; |
801 | } | 802 | } |
802 | 803 | ||
803 | static void saa7134_unregister_video(struct saa7134_dev *dev) | 804 | static void saa7134_unregister_video(struct saa7134_dev *dev) |
804 | { | 805 | { |
805 | if (dev->video_dev) { | 806 | if (dev->video_dev) { |
806 | if (-1 != dev->video_dev->minor) | 807 | if (video_is_registered(dev->video_dev)) |
807 | video_unregister_device(dev->video_dev); | 808 | video_unregister_device(dev->video_dev); |
808 | else | 809 | else |
809 | video_device_release(dev->video_dev); | 810 | video_device_release(dev->video_dev); |
810 | dev->video_dev = NULL; | 811 | dev->video_dev = NULL; |
811 | } | 812 | } |
812 | if (dev->vbi_dev) { | 813 | if (dev->vbi_dev) { |
813 | if (-1 != dev->vbi_dev->minor) | 814 | if (video_is_registered(dev->vbi_dev)) |
814 | video_unregister_device(dev->vbi_dev); | 815 | video_unregister_device(dev->vbi_dev); |
815 | else | 816 | else |
816 | video_device_release(dev->vbi_dev); | 817 | video_device_release(dev->vbi_dev); |
817 | dev->vbi_dev = NULL; | 818 | dev->vbi_dev = NULL; |
818 | } | 819 | } |
819 | if (dev->radio_dev) { | 820 | if (dev->radio_dev) { |
820 | if (-1 != dev->radio_dev->minor) | 821 | if (video_is_registered(dev->radio_dev)) |
821 | video_unregister_device(dev->radio_dev); | 822 | video_unregister_device(dev->radio_dev); |
822 | else | 823 | else |
823 | video_device_release(dev->radio_dev); | 824 | video_device_release(dev->radio_dev); |
@@ -1046,8 +1047,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1046 | dev->name); | 1047 | dev->name); |
1047 | goto fail4; | 1048 | goto fail4; |
1048 | } | 1049 | } |
1049 | printk(KERN_INFO "%s: registered device video%d [v4l2]\n", | 1050 | printk(KERN_INFO "%s: registered device %s [v4l2]\n", |
1050 | dev->name, dev->video_dev->num); | 1051 | dev->name, video_device_node_name(dev->video_dev)); |
1051 | 1052 | ||
1052 | dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); | 1053 | dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); |
1053 | 1054 | ||
@@ -1055,8 +1056,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1055 | vbi_nr[dev->nr]); | 1056 | vbi_nr[dev->nr]); |
1056 | if (err < 0) | 1057 | if (err < 0) |
1057 | goto fail4; | 1058 | goto fail4; |
1058 | printk(KERN_INFO "%s: registered device vbi%d\n", | 1059 | printk(KERN_INFO "%s: registered device %s\n", |
1059 | dev->name, dev->vbi_dev->num); | 1060 | dev->name, video_device_node_name(dev->vbi_dev)); |
1060 | 1061 | ||
1061 | if (card_has_radio(dev)) { | 1062 | if (card_has_radio(dev)) { |
1062 | dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); | 1063 | dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); |
@@ -1064,8 +1065,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1064 | radio_nr[dev->nr]); | 1065 | radio_nr[dev->nr]); |
1065 | if (err < 0) | 1066 | if (err < 0) |
1066 | goto fail4; | 1067 | goto fail4; |
1067 | printk(KERN_INFO "%s: registered device radio%d\n", | 1068 | printk(KERN_INFO "%s: registered device %s\n", |
1068 | dev->name, dev->radio_dev->num); | 1069 | dev->name, video_device_node_name(dev->radio_dev)); |
1069 | } | 1070 | } |
1070 | 1071 | ||
1071 | /* everything worked */ | 1072 | /* everything worked */ |
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 296788c3bf0e..7dfecfc6017c 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c | |||
@@ -86,19 +86,11 @@ static int ts_init_encoder(struct saa7134_dev* dev) | |||
86 | 86 | ||
87 | static int ts_open(struct file *file) | 87 | static int ts_open(struct file *file) |
88 | { | 88 | { |
89 | int minor = video_devdata(file)->minor; | 89 | struct video_device *vdev = video_devdata(file); |
90 | struct saa7134_dev *dev; | 90 | struct saa7134_dev *dev = video_drvdata(file); |
91 | int err; | 91 | int err; |
92 | 92 | ||
93 | lock_kernel(); | 93 | dprintk("open dev=%s\n", video_device_node_name(vdev)); |
94 | list_for_each_entry(dev, &saa7134_devlist, devlist) | ||
95 | if (dev->empress_dev && dev->empress_dev->minor == minor) | ||
96 | goto found; | ||
97 | unlock_kernel(); | ||
98 | return -ENODEV; | ||
99 | found: | ||
100 | |||
101 | dprintk("open minor=%d\n",minor); | ||
102 | err = -EBUSY; | 94 | err = -EBUSY; |
103 | if (!mutex_trylock(&dev->empress_tsq.vb_lock)) | 95 | if (!mutex_trylock(&dev->empress_tsq.vb_lock)) |
104 | goto done; | 96 | goto done; |
@@ -489,7 +481,6 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { | |||
489 | static struct video_device saa7134_empress_template = { | 481 | static struct video_device saa7134_empress_template = { |
490 | .name = "saa7134-empress", | 482 | .name = "saa7134-empress", |
491 | .fops = &ts_fops, | 483 | .fops = &ts_fops, |
492 | .minor = -1, | ||
493 | .ioctl_ops = &ts_ioctl_ops, | 484 | .ioctl_ops = &ts_ioctl_ops, |
494 | 485 | ||
495 | .tvnorms = SAA7134_NORMS, | 486 | .tvnorms = SAA7134_NORMS, |
@@ -531,6 +522,7 @@ static int empress_init(struct saa7134_dev *dev) | |||
531 | 522 | ||
532 | INIT_WORK(&dev->empress_workqueue, empress_signal_update); | 523 | INIT_WORK(&dev->empress_workqueue, empress_signal_update); |
533 | 524 | ||
525 | video_set_drvdata(dev->empress_dev, dev); | ||
534 | err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, | 526 | err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, |
535 | empress_nr[dev->nr]); | 527 | empress_nr[dev->nr]); |
536 | if (err < 0) { | 528 | if (err < 0) { |
@@ -540,8 +532,8 @@ static int empress_init(struct saa7134_dev *dev) | |||
540 | dev->empress_dev = NULL; | 532 | dev->empress_dev = NULL; |
541 | return err; | 533 | return err; |
542 | } | 534 | } |
543 | printk(KERN_INFO "%s: registered device video%d [mpeg]\n", | 535 | printk(KERN_INFO "%s: registered device %s [mpeg]\n", |
544 | dev->name, dev->empress_dev->num); | 536 | dev->name, video_device_node_name(dev->empress_dev)); |
545 | 537 | ||
546 | videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops, | 538 | videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops, |
547 | &dev->pci->dev, &dev->slock, | 539 | &dev->pci->dev, &dev->slock, |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 744918b1cd47..f8e985989ca0 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -127,6 +127,61 @@ static int build_key(struct saa7134_dev *dev) | |||
127 | 127 | ||
128 | /* --------------------- Chip specific I2C key builders ----------------- */ | 128 | /* --------------------- Chip specific I2C key builders ----------------- */ |
129 | 129 | ||
130 | static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
131 | { | ||
132 | int gpio; | ||
133 | int attempt = 0; | ||
134 | unsigned char b; | ||
135 | |||
136 | /* We need this to access GPI Used by the saa_readl macro. */ | ||
137 | struct saa7134_dev *dev = ir->c->adapter->algo_data; | ||
138 | |||
139 | if (dev == NULL) { | ||
140 | dprintk("get_key_flydvb_trio: " | ||
141 | "gir->c->adapter->algo_data is NULL!\n"); | ||
142 | return -EIO; | ||
143 | } | ||
144 | |||
145 | /* rising SAA7134_GPIGPRESCAN reads the status */ | ||
146 | saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
147 | saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); | ||
148 | |||
149 | gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); | ||
150 | |||
151 | if (0x40000 & ~gpio) | ||
152 | return 0; /* No button press */ | ||
153 | |||
154 | /* No button press - only before first key pressed */ | ||
155 | if (b == 0xFF) | ||
156 | return 0; | ||
157 | |||
158 | /* poll IR chip */ | ||
159 | /* weak up the IR chip */ | ||
160 | b = 0; | ||
161 | |||
162 | while (1 != i2c_master_send(ir->c, &b, 1)) { | ||
163 | if ((attempt++) < 10) { | ||
164 | /* | ||
165 | * wait a bit for next attempt - | ||
166 | * I don't know how make it better | ||
167 | */ | ||
168 | msleep(10); | ||
169 | continue; | ||
170 | } | ||
171 | i2cdprintk("send wake up byte to pic16C505 (IR chip)" | ||
172 | "failed %dx\n", attempt); | ||
173 | return -EIO; | ||
174 | } | ||
175 | if (1 != i2c_master_recv(ir->c, &b, 1)) { | ||
176 | i2cdprintk("read error\n"); | ||
177 | return -EIO; | ||
178 | } | ||
179 | |||
180 | *ir_key = b; | ||
181 | *ir_raw = b; | ||
182 | return 1; | ||
183 | } | ||
184 | |||
130 | static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, | 185 | static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, |
131 | u32 *ir_raw) | 186 | u32 *ir_raw) |
132 | { | 187 | { |
@@ -622,6 +677,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
622 | mask_keyup = 0x020000; | 677 | mask_keyup = 0x020000; |
623 | polling = 50; /* ms */ | 678 | polling = 50; /* ms */ |
624 | break; | 679 | break; |
680 | break; | ||
625 | } | 681 | } |
626 | if (NULL == ir_codes) { | 682 | if (NULL == ir_codes) { |
627 | printk("%s: Oops: IR config error [card=%d]\n", | 683 | printk("%s: Oops: IR config error [card=%d]\n", |
@@ -652,7 +708,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
652 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", | 708 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", |
653 | pci_name(dev->pci)); | 709 | pci_name(dev->pci)); |
654 | 710 | ||
655 | err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 711 | err = ir_input_init(input_dev, &ir->ir, ir_type); |
656 | if (err < 0) | 712 | if (err < 0) |
657 | goto err_out_free; | 713 | goto err_out_free; |
658 | 714 | ||
@@ -672,7 +728,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
672 | dev->remote = ir; | 728 | dev->remote = ir; |
673 | saa7134_ir_start(dev, ir); | 729 | saa7134_ir_start(dev, ir); |
674 | 730 | ||
675 | err = input_register_device(ir->dev); | 731 | err = ir_input_register(ir->dev, ir_codes); |
676 | if (err) | 732 | if (err) |
677 | goto err_out_stop; | 733 | goto err_out_stop; |
678 | 734 | ||
@@ -686,8 +742,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
686 | saa7134_ir_stop(dev); | 742 | saa7134_ir_stop(dev); |
687 | dev->remote = NULL; | 743 | dev->remote = NULL; |
688 | err_out_free: | 744 | err_out_free: |
689 | ir_input_free(input_dev); | ||
690 | input_free_device(input_dev); | ||
691 | kfree(ir); | 745 | kfree(ir); |
692 | return err; | 746 | return err; |
693 | } | 747 | } |
@@ -698,8 +752,7 @@ void saa7134_input_fini(struct saa7134_dev *dev) | |||
698 | return; | 752 | return; |
699 | 753 | ||
700 | saa7134_ir_stop(dev); | 754 | saa7134_ir_stop(dev); |
701 | ir_input_free(dev->remote->dev); | 755 | ir_input_unregister(dev->remote->dev); |
702 | input_unregister_device(dev->remote->dev); | ||
703 | kfree(dev->remote); | 756 | kfree(dev->remote); |
704 | dev->remote = NULL; | 757 | dev->remote = NULL; |
705 | } | 758 | } |
@@ -788,6 +841,12 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |||
788 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: | 841 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: |
789 | info.addr = 0x40; | 842 | info.addr = 0x40; |
790 | break; | 843 | break; |
844 | case SAA7134_BOARD_FLYDVB_TRIO: | ||
845 | dev->init_data.name = "FlyDVB Trio"; | ||
846 | dev->init_data.get_key = get_key_flydvb_trio; | ||
847 | dev->init_data.ir_codes = &ir_codes_flydvb_table; | ||
848 | info.addr = 0x0b; | ||
849 | break; | ||
791 | default: | 850 | default: |
792 | dprintk("No I2C IR support for board %x\n", dev->board); | 851 | dprintk("No I2C IR support for board %x\n", dev->board); |
793 | return; | 852 | return; |
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 35f8daa3a359..cb732640ac4a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c | |||
@@ -1326,33 +1326,26 @@ static int saa7134_resource(struct saa7134_fh *fh) | |||
1326 | 1326 | ||
1327 | static int video_open(struct file *file) | 1327 | static int video_open(struct file *file) |
1328 | { | 1328 | { |
1329 | int minor = video_devdata(file)->minor; | 1329 | struct video_device *vdev = video_devdata(file); |
1330 | struct saa7134_dev *dev; | 1330 | struct saa7134_dev *dev = video_drvdata(file); |
1331 | struct saa7134_fh *fh; | 1331 | struct saa7134_fh *fh; |
1332 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1332 | enum v4l2_buf_type type = 0; |
1333 | int radio = 0; | 1333 | int radio = 0; |
1334 | 1334 | ||
1335 | mutex_lock(&saa7134_devlist_lock); | 1335 | switch (vdev->vfl_type) { |
1336 | list_for_each_entry(dev, &saa7134_devlist, devlist) { | 1336 | case VFL_TYPE_GRABBER: |
1337 | if (dev->video_dev && (dev->video_dev->minor == minor)) | 1337 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1338 | goto found; | 1338 | break; |
1339 | if (dev->radio_dev && (dev->radio_dev->minor == minor)) { | 1339 | case VFL_TYPE_VBI: |
1340 | radio = 1; | 1340 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1341 | goto found; | 1341 | break; |
1342 | } | 1342 | case VFL_TYPE_RADIO: |
1343 | if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { | 1343 | radio = 1; |
1344 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1344 | break; |
1345 | goto found; | ||
1346 | } | ||
1347 | } | 1345 | } |
1348 | mutex_unlock(&saa7134_devlist_lock); | ||
1349 | return -ENODEV; | ||
1350 | |||
1351 | found: | ||
1352 | mutex_unlock(&saa7134_devlist_lock); | ||
1353 | 1346 | ||
1354 | dprintk("open minor=%d radio=%d type=%s\n",minor,radio, | 1347 | dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev), |
1355 | v4l2_type_names[type]); | 1348 | radio, v4l2_type_names[type]); |
1356 | 1349 | ||
1357 | /* allocate + initialize per filehandle data */ | 1350 | /* allocate + initialize per filehandle data */ |
1358 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 1351 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
@@ -2502,7 +2495,6 @@ struct video_device saa7134_video_template = { | |||
2502 | .name = "saa7134-video", | 2495 | .name = "saa7134-video", |
2503 | .fops = &video_fops, | 2496 | .fops = &video_fops, |
2504 | .ioctl_ops = &video_ioctl_ops, | 2497 | .ioctl_ops = &video_ioctl_ops, |
2505 | .minor = -1, | ||
2506 | .tvnorms = SAA7134_NORMS, | 2498 | .tvnorms = SAA7134_NORMS, |
2507 | .current_norm = V4L2_STD_PAL, | 2499 | .current_norm = V4L2_STD_PAL, |
2508 | }; | 2500 | }; |
@@ -2511,7 +2503,6 @@ struct video_device saa7134_radio_template = { | |||
2511 | .name = "saa7134-radio", | 2503 | .name = "saa7134-radio", |
2512 | .fops = &radio_fops, | 2504 | .fops = &radio_fops, |
2513 | .ioctl_ops = &radio_ioctl_ops, | 2505 | .ioctl_ops = &radio_ioctl_ops, |
2514 | .minor = -1, | ||
2515 | }; | 2506 | }; |
2516 | 2507 | ||
2517 | int saa7134_video_init1(struct saa7134_dev *dev) | 2508 | int saa7134_video_init1(struct saa7134_dev *dev) |
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 85ffc2cba039..41d0166c0f95 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c | |||
@@ -1428,8 +1428,8 @@ static int se401_probe(struct usb_interface *intf, | |||
1428 | err("video_register_device failed"); | 1428 | err("video_register_device failed"); |
1429 | return -EIO; | 1429 | return -EIO; |
1430 | } | 1430 | } |
1431 | dev_info(&intf->dev, "registered new video device: video%d\n", | 1431 | dev_info(&intf->dev, "registered new video device: %s\n", |
1432 | se401->vdev.num); | 1432 | video_device_node_name(&se401->vdev)); |
1433 | 1433 | ||
1434 | usb_set_intfdata(intf, se401); | 1434 | usb_set_intfdata(intf, se401); |
1435 | return 0; | 1435 | return 0; |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 961e4484d721..d69363f0d8c9 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <media/soc_camera.h> | 38 | #include <media/soc_camera.h> |
39 | #include <media/sh_mobile_ceu.h> | 39 | #include <media/sh_mobile_ceu.h> |
40 | #include <media/videobuf-dma-contig.h> | 40 | #include <media/videobuf-dma-contig.h> |
41 | #include <media/v4l2-mediabus.h> | ||
42 | #include <media/soc_mediabus.h> | ||
41 | 43 | ||
42 | /* register offsets for sh7722 / sh7723 */ | 44 | /* register offsets for sh7722 / sh7723 */ |
43 | 45 | ||
@@ -85,7 +87,7 @@ | |||
85 | /* per video frame buffer */ | 87 | /* per video frame buffer */ |
86 | struct sh_mobile_ceu_buffer { | 88 | struct sh_mobile_ceu_buffer { |
87 | struct videobuf_buffer vb; /* v4l buffer must be first */ | 89 | struct videobuf_buffer vb; /* v4l buffer must be first */ |
88 | const struct soc_camera_data_format *fmt; | 90 | enum v4l2_mbus_pixelcode code; |
89 | }; | 91 | }; |
90 | 92 | ||
91 | struct sh_mobile_ceu_dev { | 93 | struct sh_mobile_ceu_dev { |
@@ -105,7 +107,8 @@ struct sh_mobile_ceu_dev { | |||
105 | 107 | ||
106 | u32 cflcr; | 108 | u32 cflcr; |
107 | 109 | ||
108 | unsigned int is_interlaced:1; | 110 | enum v4l2_field field; |
111 | |||
109 | unsigned int image_mode:1; | 112 | unsigned int image_mode:1; |
110 | unsigned int is_16bit:1; | 113 | unsigned int is_16bit:1; |
111 | }; | 114 | }; |
@@ -114,8 +117,8 @@ struct sh_mobile_ceu_cam { | |||
114 | struct v4l2_rect ceu_rect; | 117 | struct v4l2_rect ceu_rect; |
115 | unsigned int cam_width; | 118 | unsigned int cam_width; |
116 | unsigned int cam_height; | 119 | unsigned int cam_height; |
117 | const struct soc_camera_data_format *extra_fmt; | 120 | const struct soc_mbus_pixelfmt *extra_fmt; |
118 | const struct soc_camera_data_format *camera_fmt; | 121 | enum v4l2_mbus_pixelcode code; |
119 | }; | 122 | }; |
120 | 123 | ||
121 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) | 124 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) |
@@ -197,16 +200,19 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, | |||
197 | struct soc_camera_device *icd = vq->priv_data; | 200 | struct soc_camera_device *icd = vq->priv_data; |
198 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 201 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
199 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 202 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
200 | int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; | 203 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
204 | icd->current_fmt->host_fmt); | ||
205 | |||
206 | if (bytes_per_line < 0) | ||
207 | return bytes_per_line; | ||
201 | 208 | ||
202 | *size = PAGE_ALIGN(icd->user_width * icd->user_height * | 209 | *size = bytes_per_line * icd->user_height; |
203 | bytes_per_pixel); | ||
204 | 210 | ||
205 | if (0 == *count) | 211 | if (0 == *count) |
206 | *count = 2; | 212 | *count = 2; |
207 | 213 | ||
208 | if (pcdev->video_limit) { | 214 | if (pcdev->video_limit) { |
209 | while (*size * *count > pcdev->video_limit) | 215 | while (PAGE_ALIGN(*size) * *count > pcdev->video_limit) |
210 | (*count)--; | 216 | (*count)--; |
211 | } | 217 | } |
212 | 218 | ||
@@ -249,10 +255,13 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
249 | { | 255 | { |
250 | struct soc_camera_device *icd = pcdev->icd; | 256 | struct soc_camera_device *icd = pcdev->icd; |
251 | dma_addr_t phys_addr_top, phys_addr_bottom; | 257 | dma_addr_t phys_addr_top, phys_addr_bottom; |
258 | unsigned long top1, top2; | ||
259 | unsigned long bottom1, bottom2; | ||
252 | u32 status; | 260 | u32 status; |
253 | int ret = 0; | 261 | int ret = 0; |
254 | 262 | ||
255 | /* The hardware is _very_ picky about this sequence. Especially | 263 | /* |
264 | * The hardware is _very_ picky about this sequence. Especially | ||
256 | * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge | 265 | * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge |
257 | * several not-so-well documented interrupt sources in CETCR. | 266 | * several not-so-well documented interrupt sources in CETCR. |
258 | */ | 267 | */ |
@@ -276,25 +285,36 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
276 | if (!pcdev->active) | 285 | if (!pcdev->active) |
277 | return ret; | 286 | return ret; |
278 | 287 | ||
288 | if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { | ||
289 | top1 = CDBYR; | ||
290 | top2 = CDBCR; | ||
291 | bottom1 = CDAYR; | ||
292 | bottom2 = CDACR; | ||
293 | } else { | ||
294 | top1 = CDAYR; | ||
295 | top2 = CDACR; | ||
296 | bottom1 = CDBYR; | ||
297 | bottom2 = CDBCR; | ||
298 | } | ||
299 | |||
279 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); | 300 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); |
280 | ceu_write(pcdev, CDAYR, phys_addr_top); | 301 | ceu_write(pcdev, top1, phys_addr_top); |
281 | if (pcdev->is_interlaced) { | 302 | if (V4L2_FIELD_NONE != pcdev->field) { |
282 | phys_addr_bottom = phys_addr_top + icd->user_width; | 303 | phys_addr_bottom = phys_addr_top + icd->user_width; |
283 | ceu_write(pcdev, CDBYR, phys_addr_bottom); | 304 | ceu_write(pcdev, bottom1, phys_addr_bottom); |
284 | } | 305 | } |
285 | 306 | ||
286 | switch (icd->current_fmt->fourcc) { | 307 | switch (icd->current_fmt->host_fmt->fourcc) { |
287 | case V4L2_PIX_FMT_NV12: | 308 | case V4L2_PIX_FMT_NV12: |
288 | case V4L2_PIX_FMT_NV21: | 309 | case V4L2_PIX_FMT_NV21: |
289 | case V4L2_PIX_FMT_NV16: | 310 | case V4L2_PIX_FMT_NV16: |
290 | case V4L2_PIX_FMT_NV61: | 311 | case V4L2_PIX_FMT_NV61: |
291 | phys_addr_top += icd->user_width * | 312 | phys_addr_top += icd->user_width * |
292 | icd->user_height; | 313 | icd->user_height; |
293 | ceu_write(pcdev, CDACR, phys_addr_top); | 314 | ceu_write(pcdev, top2, phys_addr_top); |
294 | if (pcdev->is_interlaced) { | 315 | if (V4L2_FIELD_NONE != pcdev->field) { |
295 | phys_addr_bottom = phys_addr_top + | 316 | phys_addr_bottom = phys_addr_top + icd->user_width; |
296 | icd->user_width; | 317 | ceu_write(pcdev, bottom2, phys_addr_bottom); |
297 | ceu_write(pcdev, CDBCR, phys_addr_bottom); | ||
298 | } | 318 | } |
299 | } | 319 | } |
300 | 320 | ||
@@ -310,8 +330,13 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
310 | { | 330 | { |
311 | struct soc_camera_device *icd = vq->priv_data; | 331 | struct soc_camera_device *icd = vq->priv_data; |
312 | struct sh_mobile_ceu_buffer *buf; | 332 | struct sh_mobile_ceu_buffer *buf; |
333 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
334 | icd->current_fmt->host_fmt); | ||
313 | int ret; | 335 | int ret; |
314 | 336 | ||
337 | if (bytes_per_line < 0) | ||
338 | return bytes_per_line; | ||
339 | |||
315 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); | 340 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); |
316 | 341 | ||
317 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, | 342 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, |
@@ -321,25 +346,27 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
321 | WARN_ON(!list_empty(&vb->queue)); | 346 | WARN_ON(!list_empty(&vb->queue)); |
322 | 347 | ||
323 | #ifdef DEBUG | 348 | #ifdef DEBUG |
324 | /* This can be useful if you want to see if we actually fill | 349 | /* |
325 | * the buffer with something */ | 350 | * This can be useful if you want to see if we actually fill |
351 | * the buffer with something | ||
352 | */ | ||
326 | memset((void *)vb->baddr, 0xaa, vb->bsize); | 353 | memset((void *)vb->baddr, 0xaa, vb->bsize); |
327 | #endif | 354 | #endif |
328 | 355 | ||
329 | BUG_ON(NULL == icd->current_fmt); | 356 | BUG_ON(NULL == icd->current_fmt); |
330 | 357 | ||
331 | if (buf->fmt != icd->current_fmt || | 358 | if (buf->code != icd->current_fmt->code || |
332 | vb->width != icd->user_width || | 359 | vb->width != icd->user_width || |
333 | vb->height != icd->user_height || | 360 | vb->height != icd->user_height || |
334 | vb->field != field) { | 361 | vb->field != field) { |
335 | buf->fmt = icd->current_fmt; | 362 | buf->code = icd->current_fmt->code; |
336 | vb->width = icd->user_width; | 363 | vb->width = icd->user_width; |
337 | vb->height = icd->user_height; | 364 | vb->height = icd->user_height; |
338 | vb->field = field; | 365 | vb->field = field; |
339 | vb->state = VIDEOBUF_NEEDS_INIT; | 366 | vb->state = VIDEOBUF_NEEDS_INIT; |
340 | } | 367 | } |
341 | 368 | ||
342 | vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); | 369 | vb->size = vb->height * bytes_per_line; |
343 | if (0 != vb->baddr && vb->bsize < vb->size) { | 370 | if (0 != vb->baddr && vb->bsize < vb->size) { |
344 | ret = -EINVAL; | 371 | ret = -EINVAL; |
345 | goto out; | 372 | goto out; |
@@ -456,6 +483,7 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
456 | { | 483 | { |
457 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 484 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
458 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 485 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
486 | int ret; | ||
459 | 487 | ||
460 | if (pcdev->icd) | 488 | if (pcdev->icd) |
461 | return -EBUSY; | 489 | return -EBUSY; |
@@ -466,9 +494,11 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
466 | 494 | ||
467 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 495 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
468 | 496 | ||
469 | pcdev->icd = icd; | 497 | ret = sh_mobile_ceu_soft_reset(pcdev); |
498 | if (!ret) | ||
499 | pcdev->icd = icd; | ||
470 | 500 | ||
471 | return sh_mobile_ceu_soft_reset(pcdev); | 501 | return ret; |
472 | } | 502 | } |
473 | 503 | ||
474 | /* Called with .video_lock held */ | 504 | /* Called with .video_lock held */ |
@@ -558,24 +588,35 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, | |||
558 | in_width *= 2; | 588 | in_width *= 2; |
559 | left_offset *= 2; | 589 | left_offset *= 2; |
560 | } | 590 | } |
561 | width = cdwdr_width = out_width; | 591 | width = out_width; |
592 | cdwdr_width = out_width; | ||
562 | } else { | 593 | } else { |
563 | unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3; | 594 | int bytes_per_line = soc_mbus_bytes_per_line(out_width, |
595 | icd->current_fmt->host_fmt); | ||
596 | unsigned int w_factor; | ||
564 | 597 | ||
565 | width = out_width * w_factor / 2; | 598 | width = out_width; |
566 | 599 | ||
567 | if (!pcdev->is_16bit) | 600 | switch (icd->current_fmt->host_fmt->packing) { |
568 | w_factor *= 2; | 601 | case SOC_MBUS_PACKING_2X8_PADHI: |
602 | w_factor = 2; | ||
603 | break; | ||
604 | default: | ||
605 | w_factor = 1; | ||
606 | } | ||
569 | 607 | ||
570 | in_width = rect->width * w_factor / 2; | 608 | in_width = rect->width * w_factor; |
571 | left_offset = left_offset * w_factor / 2; | 609 | left_offset = left_offset * w_factor; |
572 | 610 | ||
573 | cdwdr_width = width * 2; | 611 | if (bytes_per_line < 0) |
612 | cdwdr_width = out_width; | ||
613 | else | ||
614 | cdwdr_width = bytes_per_line; | ||
574 | } | 615 | } |
575 | 616 | ||
576 | height = out_height; | 617 | height = out_height; |
577 | in_height = rect->height; | 618 | in_height = rect->height; |
578 | if (pcdev->is_interlaced) { | 619 | if (V4L2_FIELD_NONE != pcdev->field) { |
579 | height /= 2; | 620 | height /= 2; |
580 | in_height /= 2; | 621 | in_height /= 2; |
581 | top_offset /= 2; | 622 | top_offset /= 2; |
@@ -646,6 +687,23 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
646 | if (!common_flags) | 687 | if (!common_flags) |
647 | return -EINVAL; | 688 | return -EINVAL; |
648 | 689 | ||
690 | /* Make choises, based on platform preferences */ | ||
691 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | ||
692 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | ||
693 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) | ||
694 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | ||
695 | else | ||
696 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | ||
697 | } | ||
698 | |||
699 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | ||
700 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | ||
701 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) | ||
702 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | ||
703 | else | ||
704 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | ||
705 | } | ||
706 | |||
649 | ret = icd->ops->set_bus_param(icd, common_flags); | 707 | ret = icd->ops->set_bus_param(icd, common_flags); |
650 | if (ret < 0) | 708 | if (ret < 0) |
651 | return ret; | 709 | return ret; |
@@ -667,24 +725,24 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
667 | value = 0x00000010; /* data fetch by default */ | 725 | value = 0x00000010; /* data fetch by default */ |
668 | yuv_lineskip = 0; | 726 | yuv_lineskip = 0; |
669 | 727 | ||
670 | switch (icd->current_fmt->fourcc) { | 728 | switch (icd->current_fmt->host_fmt->fourcc) { |
671 | case V4L2_PIX_FMT_NV12: | 729 | case V4L2_PIX_FMT_NV12: |
672 | case V4L2_PIX_FMT_NV21: | 730 | case V4L2_PIX_FMT_NV21: |
673 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ | 731 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ |
674 | /* fall-through */ | 732 | /* fall-through */ |
675 | case V4L2_PIX_FMT_NV16: | 733 | case V4L2_PIX_FMT_NV16: |
676 | case V4L2_PIX_FMT_NV61: | 734 | case V4L2_PIX_FMT_NV61: |
677 | switch (cam->camera_fmt->fourcc) { | 735 | switch (cam->code) { |
678 | case V4L2_PIX_FMT_UYVY: | 736 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
679 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ | 737 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ |
680 | break; | 738 | break; |
681 | case V4L2_PIX_FMT_VYUY: | 739 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
682 | value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ | 740 | value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ |
683 | break; | 741 | break; |
684 | case V4L2_PIX_FMT_YUYV: | 742 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
685 | value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ | 743 | value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ |
686 | break; | 744 | break; |
687 | case V4L2_PIX_FMT_YVYU: | 745 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
688 | value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ | 746 | value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ |
689 | break; | 747 | break; |
690 | default: | 748 | default: |
@@ -692,8 +750,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
692 | } | 750 | } |
693 | } | 751 | } |
694 | 752 | ||
695 | if (icd->current_fmt->fourcc == V4L2_PIX_FMT_NV21 || | 753 | if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || |
696 | icd->current_fmt->fourcc == V4L2_PIX_FMT_NV61) | 754 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) |
697 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ | 755 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ |
698 | 756 | ||
699 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 757 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
@@ -702,14 +760,27 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
702 | ceu_write(pcdev, CAMCR, value); | 760 | ceu_write(pcdev, CAMCR, value); |
703 | 761 | ||
704 | ceu_write(pcdev, CAPCR, 0x00300000); | 762 | ceu_write(pcdev, CAPCR, 0x00300000); |
705 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); | 763 | |
764 | switch (pcdev->field) { | ||
765 | case V4L2_FIELD_INTERLACED_TB: | ||
766 | value = 0x101; | ||
767 | break; | ||
768 | case V4L2_FIELD_INTERLACED_BT: | ||
769 | value = 0x102; | ||
770 | break; | ||
771 | default: | ||
772 | value = 0; | ||
773 | break; | ||
774 | } | ||
775 | ceu_write(pcdev, CAIFR, value); | ||
706 | 776 | ||
707 | sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); | 777 | sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); |
708 | mdelay(1); | 778 | mdelay(1); |
709 | 779 | ||
710 | ceu_write(pcdev, CFLCR, pcdev->cflcr); | 780 | ceu_write(pcdev, CFLCR, pcdev->cflcr); |
711 | 781 | ||
712 | /* A few words about byte order (observed in Big Endian mode) | 782 | /* |
783 | * A few words about byte order (observed in Big Endian mode) | ||
713 | * | 784 | * |
714 | * In data fetch mode bytes are received in chunks of 8 bytes. | 785 | * In data fetch mode bytes are received in chunks of 8 bytes. |
715 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) | 786 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) |
@@ -739,7 +810,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
739 | return 0; | 810 | return 0; |
740 | } | 811 | } |
741 | 812 | ||
742 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) | 813 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, |
814 | unsigned char buswidth) | ||
743 | { | 815 | { |
744 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 816 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
745 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 817 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
@@ -748,48 +820,75 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) | |||
748 | camera_flags = icd->ops->query_bus_param(icd); | 820 | camera_flags = icd->ops->query_bus_param(icd); |
749 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 821 | common_flags = soc_camera_bus_param_compatible(camera_flags, |
750 | make_bus_param(pcdev)); | 822 | make_bus_param(pcdev)); |
751 | if (!common_flags) | 823 | if (!common_flags || buswidth > 16 || |
824 | (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) | ||
752 | return -EINVAL; | 825 | return -EINVAL; |
753 | 826 | ||
754 | return 0; | 827 | return 0; |
755 | } | 828 | } |
756 | 829 | ||
757 | static const struct soc_camera_data_format sh_mobile_ceu_formats[] = { | 830 | static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { |
758 | { | ||
759 | .name = "NV12", | ||
760 | .depth = 12, | ||
761 | .fourcc = V4L2_PIX_FMT_NV12, | ||
762 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
763 | }, | ||
764 | { | ||
765 | .name = "NV21", | ||
766 | .depth = 12, | ||
767 | .fourcc = V4L2_PIX_FMT_NV21, | ||
768 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
769 | }, | ||
770 | { | ||
771 | .name = "NV16", | ||
772 | .depth = 16, | ||
773 | .fourcc = V4L2_PIX_FMT_NV16, | ||
774 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
775 | }, | ||
776 | { | 831 | { |
777 | .name = "NV61", | 832 | .fourcc = V4L2_PIX_FMT_NV12, |
778 | .depth = 16, | 833 | .name = "NV12", |
779 | .fourcc = V4L2_PIX_FMT_NV61, | 834 | .bits_per_sample = 12, |
780 | .colorspace = V4L2_COLORSPACE_JPEG, | 835 | .packing = SOC_MBUS_PACKING_NONE, |
836 | .order = SOC_MBUS_ORDER_LE, | ||
837 | }, { | ||
838 | .fourcc = V4L2_PIX_FMT_NV21, | ||
839 | .name = "NV21", | ||
840 | .bits_per_sample = 12, | ||
841 | .packing = SOC_MBUS_PACKING_NONE, | ||
842 | .order = SOC_MBUS_ORDER_LE, | ||
843 | }, { | ||
844 | .fourcc = V4L2_PIX_FMT_NV16, | ||
845 | .name = "NV16", | ||
846 | .bits_per_sample = 16, | ||
847 | .packing = SOC_MBUS_PACKING_NONE, | ||
848 | .order = SOC_MBUS_ORDER_LE, | ||
849 | }, { | ||
850 | .fourcc = V4L2_PIX_FMT_NV61, | ||
851 | .name = "NV61", | ||
852 | .bits_per_sample = 16, | ||
853 | .packing = SOC_MBUS_PACKING_NONE, | ||
854 | .order = SOC_MBUS_ORDER_LE, | ||
781 | }, | 855 | }, |
782 | }; | 856 | }; |
783 | 857 | ||
858 | /* This will be corrected as we get more formats */ | ||
859 | static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
860 | { | ||
861 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
862 | (fmt->bits_per_sample == 8 && | ||
863 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
864 | (fmt->bits_per_sample > 8 && | ||
865 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
866 | } | ||
867 | |||
784 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | 868 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, |
785 | struct soc_camera_format_xlate *xlate) | 869 | struct soc_camera_format_xlate *xlate) |
786 | { | 870 | { |
871 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
787 | struct device *dev = icd->dev.parent; | 872 | struct device *dev = icd->dev.parent; |
788 | int ret, k, n; | 873 | int ret, k, n; |
789 | int formats = 0; | 874 | int formats = 0; |
790 | struct sh_mobile_ceu_cam *cam; | 875 | struct sh_mobile_ceu_cam *cam; |
876 | enum v4l2_mbus_pixelcode code; | ||
877 | const struct soc_mbus_pixelfmt *fmt; | ||
791 | 878 | ||
792 | ret = sh_mobile_ceu_try_bus_param(icd); | 879 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); |
880 | if (ret < 0) | ||
881 | /* No more formats */ | ||
882 | return 0; | ||
883 | |||
884 | fmt = soc_mbus_get_fmtdesc(code); | ||
885 | if (!fmt) { | ||
886 | dev_err(icd->dev.parent, | ||
887 | "Invalid format code #%d: %d\n", idx, code); | ||
888 | return -EINVAL; | ||
889 | } | ||
890 | |||
891 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | ||
793 | if (ret < 0) | 892 | if (ret < 0) |
794 | return 0; | 893 | return 0; |
795 | 894 | ||
@@ -807,13 +906,13 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
807 | if (!idx) | 906 | if (!idx) |
808 | cam->extra_fmt = NULL; | 907 | cam->extra_fmt = NULL; |
809 | 908 | ||
810 | switch (icd->formats[idx].fourcc) { | 909 | switch (code) { |
811 | case V4L2_PIX_FMT_UYVY: | 910 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
812 | case V4L2_PIX_FMT_VYUY: | 911 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
813 | case V4L2_PIX_FMT_YUYV: | 912 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
814 | case V4L2_PIX_FMT_YVYU: | 913 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
815 | if (cam->extra_fmt) | 914 | if (cam->extra_fmt) |
816 | goto add_single_format; | 915 | break; |
817 | 916 | ||
818 | /* | 917 | /* |
819 | * Our case is simple so far: for any of the above four camera | 918 | * Our case is simple so far: for any of the above four camera |
@@ -824,32 +923,31 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
824 | * the host_priv pointer and check whether the format you're | 923 | * the host_priv pointer and check whether the format you're |
825 | * going to add now is already there. | 924 | * going to add now is already there. |
826 | */ | 925 | */ |
827 | cam->extra_fmt = (void *)sh_mobile_ceu_formats; | 926 | cam->extra_fmt = sh_mobile_ceu_formats; |
828 | 927 | ||
829 | n = ARRAY_SIZE(sh_mobile_ceu_formats); | 928 | n = ARRAY_SIZE(sh_mobile_ceu_formats); |
830 | formats += n; | 929 | formats += n; |
831 | for (k = 0; xlate && k < n; k++) { | 930 | for (k = 0; xlate && k < n; k++) { |
832 | xlate->host_fmt = &sh_mobile_ceu_formats[k]; | 931 | xlate->host_fmt = &sh_mobile_ceu_formats[k]; |
833 | xlate->cam_fmt = icd->formats + idx; | 932 | xlate->code = code; |
834 | xlate->buswidth = icd->formats[idx].depth; | ||
835 | xlate++; | 933 | xlate++; |
836 | dev_dbg(dev, "Providing format %s using %s\n", | 934 | dev_dbg(dev, "Providing format %s using code %d\n", |
837 | sh_mobile_ceu_formats[k].name, | 935 | sh_mobile_ceu_formats[k].name, code); |
838 | icd->formats[idx].name); | ||
839 | } | 936 | } |
937 | break; | ||
840 | default: | 938 | default: |
841 | add_single_format: | 939 | if (!sh_mobile_ceu_packing_supported(fmt)) |
842 | /* Generic pass-through */ | 940 | return 0; |
843 | formats++; | 941 | } |
844 | if (xlate) { | 942 | |
845 | xlate->host_fmt = icd->formats + idx; | 943 | /* Generic pass-through */ |
846 | xlate->cam_fmt = icd->formats + idx; | 944 | formats++; |
847 | xlate->buswidth = icd->formats[idx].depth; | 945 | if (xlate) { |
848 | xlate++; | 946 | xlate->host_fmt = fmt; |
849 | dev_dbg(dev, | 947 | xlate->code = code; |
850 | "Providing format %s in pass-through mode\n", | 948 | xlate++; |
851 | icd->formats[idx].name); | 949 | dev_dbg(dev, "Providing format %s in pass-through mode\n", |
852 | } | 950 | xlate->host_fmt->name); |
853 | } | 951 | } |
854 | 952 | ||
855 | return formats; | 953 | return formats; |
@@ -1029,17 +1127,15 @@ static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop, | |||
1029 | static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, | 1127 | static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, |
1030 | unsigned int *scale_h, unsigned int *scale_v) | 1128 | unsigned int *scale_h, unsigned int *scale_v) |
1031 | { | 1129 | { |
1032 | struct v4l2_format f; | 1130 | struct v4l2_mbus_framefmt mf; |
1033 | int ret; | 1131 | int ret; |
1034 | 1132 | ||
1035 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1133 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
1036 | |||
1037 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1038 | if (ret < 0) | 1134 | if (ret < 0) |
1039 | return ret; | 1135 | return ret; |
1040 | 1136 | ||
1041 | *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width); | 1137 | *scale_h = calc_generic_scale(rect->width, mf.width); |
1042 | *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height); | 1138 | *scale_v = calc_generic_scale(rect->height, mf.height); |
1043 | 1139 | ||
1044 | return 0; | 1140 | return 0; |
1045 | } | 1141 | } |
@@ -1054,32 +1150,29 @@ static int get_camera_subwin(struct soc_camera_device *icd, | |||
1054 | if (!ceu_rect->width) { | 1150 | if (!ceu_rect->width) { |
1055 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1151 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1056 | struct device *dev = icd->dev.parent; | 1152 | struct device *dev = icd->dev.parent; |
1057 | struct v4l2_format f; | 1153 | struct v4l2_mbus_framefmt mf; |
1058 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1059 | int ret; | 1154 | int ret; |
1060 | /* First time */ | 1155 | /* First time */ |
1061 | 1156 | ||
1062 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1157 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
1063 | |||
1064 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1065 | if (ret < 0) | 1158 | if (ret < 0) |
1066 | return ret; | 1159 | return ret; |
1067 | 1160 | ||
1068 | dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height); | 1161 | dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); |
1069 | 1162 | ||
1070 | if (pix->width > 2560) { | 1163 | if (mf.width > 2560) { |
1071 | ceu_rect->width = 2560; | 1164 | ceu_rect->width = 2560; |
1072 | ceu_rect->left = (pix->width - 2560) / 2; | 1165 | ceu_rect->left = (mf.width - 2560) / 2; |
1073 | } else { | 1166 | } else { |
1074 | ceu_rect->width = pix->width; | 1167 | ceu_rect->width = mf.width; |
1075 | ceu_rect->left = 0; | 1168 | ceu_rect->left = 0; |
1076 | } | 1169 | } |
1077 | 1170 | ||
1078 | if (pix->height > 1920) { | 1171 | if (mf.height > 1920) { |
1079 | ceu_rect->height = 1920; | 1172 | ceu_rect->height = 1920; |
1080 | ceu_rect->top = (pix->height - 1920) / 2; | 1173 | ceu_rect->top = (mf.height - 1920) / 2; |
1081 | } else { | 1174 | } else { |
1082 | ceu_rect->height = pix->height; | 1175 | ceu_rect->height = mf.height; |
1083 | ceu_rect->top = 0; | 1176 | ceu_rect->top = 0; |
1084 | } | 1177 | } |
1085 | 1178 | ||
@@ -1096,13 +1189,12 @@ static int get_camera_subwin(struct soc_camera_device *icd, | |||
1096 | return 0; | 1189 | return 0; |
1097 | } | 1190 | } |
1098 | 1191 | ||
1099 | static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | 1192 | static int client_s_fmt(struct soc_camera_device *icd, |
1100 | bool ceu_can_scale) | 1193 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) |
1101 | { | 1194 | { |
1102 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1195 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1103 | struct device *dev = icd->dev.parent; | 1196 | struct device *dev = icd->dev.parent; |
1104 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1197 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; |
1105 | unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h; | ||
1106 | unsigned int max_width, max_height; | 1198 | unsigned int max_width, max_height; |
1107 | struct v4l2_cropcap cap; | 1199 | struct v4l2_cropcap cap; |
1108 | int ret; | 1200 | int ret; |
@@ -1116,29 +1208,29 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | |||
1116 | max_width = min(cap.bounds.width, 2560); | 1208 | max_width = min(cap.bounds.width, 2560); |
1117 | max_height = min(cap.bounds.height, 1920); | 1209 | max_height = min(cap.bounds.height, 1920); |
1118 | 1210 | ||
1119 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 1211 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); |
1120 | if (ret < 0) | 1212 | if (ret < 0) |
1121 | return ret; | 1213 | return ret; |
1122 | 1214 | ||
1123 | dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height); | 1215 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); |
1124 | 1216 | ||
1125 | if ((width == pix->width && height == pix->height) || !ceu_can_scale) | 1217 | if ((width == mf->width && height == mf->height) || !ceu_can_scale) |
1126 | return 0; | 1218 | return 0; |
1127 | 1219 | ||
1128 | /* Camera set a format, but geometry is not precise, try to improve */ | 1220 | /* Camera set a format, but geometry is not precise, try to improve */ |
1129 | tmp_w = pix->width; | 1221 | tmp_w = mf->width; |
1130 | tmp_h = pix->height; | 1222 | tmp_h = mf->height; |
1131 | 1223 | ||
1132 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ | 1224 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ |
1133 | while ((width > tmp_w || height > tmp_h) && | 1225 | while ((width > tmp_w || height > tmp_h) && |
1134 | tmp_w < max_width && tmp_h < max_height) { | 1226 | tmp_w < max_width && tmp_h < max_height) { |
1135 | tmp_w = min(2 * tmp_w, max_width); | 1227 | tmp_w = min(2 * tmp_w, max_width); |
1136 | tmp_h = min(2 * tmp_h, max_height); | 1228 | tmp_h = min(2 * tmp_h, max_height); |
1137 | pix->width = tmp_w; | 1229 | mf->width = tmp_w; |
1138 | pix->height = tmp_h; | 1230 | mf->height = tmp_h; |
1139 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 1231 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); |
1140 | dev_geo(dev, "Camera scaled to %ux%u\n", | 1232 | dev_geo(dev, "Camera scaled to %ux%u\n", |
1141 | pix->width, pix->height); | 1233 | mf->width, mf->height); |
1142 | if (ret < 0) { | 1234 | if (ret < 0) { |
1143 | /* This shouldn't happen */ | 1235 | /* This shouldn't happen */ |
1144 | dev_err(dev, "Client failed to set format: %d\n", ret); | 1236 | dev_err(dev, "Client failed to set format: %d\n", ret); |
@@ -1156,27 +1248,26 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | |||
1156 | */ | 1248 | */ |
1157 | static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, | 1249 | static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, |
1158 | struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, | 1250 | struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, |
1159 | struct v4l2_format *f, bool ceu_can_scale) | 1251 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) |
1160 | { | 1252 | { |
1161 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1253 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1162 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1254 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1163 | struct device *dev = icd->dev.parent; | 1255 | struct device *dev = icd->dev.parent; |
1164 | struct v4l2_format f_tmp = *f; | 1256 | struct v4l2_mbus_framefmt mf_tmp = *mf; |
1165 | struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix; | ||
1166 | unsigned int scale_h, scale_v; | 1257 | unsigned int scale_h, scale_v; |
1167 | int ret; | 1258 | int ret; |
1168 | 1259 | ||
1169 | /* 5. Apply iterative camera S_FMT for camera user window. */ | 1260 | /* 5. Apply iterative camera S_FMT for camera user window. */ |
1170 | ret = client_s_fmt(icd, &f_tmp, ceu_can_scale); | 1261 | ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); |
1171 | if (ret < 0) | 1262 | if (ret < 0) |
1172 | return ret; | 1263 | return ret; |
1173 | 1264 | ||
1174 | dev_geo(dev, "5: camera scaled to %ux%u\n", | 1265 | dev_geo(dev, "5: camera scaled to %ux%u\n", |
1175 | pix_tmp->width, pix_tmp->height); | 1266 | mf_tmp.width, mf_tmp.height); |
1176 | 1267 | ||
1177 | /* 6. Retrieve camera output window (g_fmt) */ | 1268 | /* 6. Retrieve camera output window (g_fmt) */ |
1178 | 1269 | ||
1179 | /* unneeded - it is already in "f_tmp" */ | 1270 | /* unneeded - it is already in "mf_tmp" */ |
1180 | 1271 | ||
1181 | /* 7. Calculate new camera scales. */ | 1272 | /* 7. Calculate new camera scales. */ |
1182 | ret = get_camera_scales(sd, rect, &scale_h, &scale_v); | 1273 | ret = get_camera_scales(sd, rect, &scale_h, &scale_v); |
@@ -1185,10 +1276,11 @@ static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, | |||
1185 | 1276 | ||
1186 | dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); | 1277 | dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); |
1187 | 1278 | ||
1188 | cam->cam_width = pix_tmp->width; | 1279 | cam->cam_width = mf_tmp.width; |
1189 | cam->cam_height = pix_tmp->height; | 1280 | cam->cam_height = mf_tmp.height; |
1190 | f->fmt.pix.width = pix_tmp->width; | 1281 | mf->width = mf_tmp.width; |
1191 | f->fmt.pix.height = pix_tmp->height; | 1282 | mf->height = mf_tmp.height; |
1283 | mf->colorspace = mf_tmp.colorspace; | ||
1192 | 1284 | ||
1193 | /* | 1285 | /* |
1194 | * 8. Calculate new CEU crop - apply camera scales to previously | 1286 | * 8. Calculate new CEU crop - apply camera scales to previously |
@@ -1252,8 +1344,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1252 | struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; | 1344 | struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; |
1253 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1345 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1254 | struct device *dev = icd->dev.parent; | 1346 | struct device *dev = icd->dev.parent; |
1255 | struct v4l2_format f; | 1347 | struct v4l2_mbus_framefmt mf; |
1256 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1257 | unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, | 1348 | unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, |
1258 | out_width, out_height; | 1349 | out_width, out_height; |
1259 | u32 capsr, cflcr; | 1350 | u32 capsr, cflcr; |
@@ -1302,26 +1393,25 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1302 | * 5. Using actual input window and calculated combined scales calculate | 1393 | * 5. Using actual input window and calculated combined scales calculate |
1303 | * camera target output window. | 1394 | * camera target output window. |
1304 | */ | 1395 | */ |
1305 | pix->width = scale_down(cam_rect->width, scale_comb_h); | 1396 | mf.width = scale_down(cam_rect->width, scale_comb_h); |
1306 | pix->height = scale_down(cam_rect->height, scale_comb_v); | 1397 | mf.height = scale_down(cam_rect->height, scale_comb_v); |
1307 | 1398 | ||
1308 | dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height); | 1399 | dev_geo(dev, "5: camera target %ux%u\n", mf.width, mf.height); |
1309 | 1400 | ||
1310 | /* 6. - 9. */ | 1401 | /* 6. - 9. */ |
1311 | pix->pixelformat = cam->camera_fmt->fourcc; | 1402 | mf.code = cam->code; |
1312 | pix->colorspace = cam->camera_fmt->colorspace; | 1403 | mf.field = pcdev->field; |
1313 | 1404 | ||
1314 | capsr = capture_save_reset(pcdev); | 1405 | capsr = capture_save_reset(pcdev); |
1315 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | 1406 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); |
1316 | 1407 | ||
1317 | /* Make relative to camera rectangle */ | 1408 | /* Make relative to camera rectangle */ |
1318 | rect->left -= cam_rect->left; | 1409 | rect->left -= cam_rect->left; |
1319 | rect->top -= cam_rect->top; | 1410 | rect->top -= cam_rect->top; |
1320 | 1411 | ||
1321 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1412 | ret = client_scale(icd, cam_rect, rect, ceu_rect, &mf, |
1322 | 1413 | pcdev->image_mode && | |
1323 | ret = client_scale(icd, cam_rect, rect, ceu_rect, &f, | 1414 | V4L2_FIELD_NONE == pcdev->field); |
1324 | pcdev->image_mode && !pcdev->is_interlaced); | ||
1325 | 1415 | ||
1326 | dev_geo(dev, "6-9: %d\n", ret); | 1416 | dev_geo(dev, "6-9: %d\n", ret); |
1327 | 1417 | ||
@@ -1368,8 +1458,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1368 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 1458 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
1369 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1459 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1370 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1460 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1371 | struct v4l2_format cam_f = *f; | 1461 | struct v4l2_mbus_framefmt mf; |
1372 | struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix; | ||
1373 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1462 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1374 | struct device *dev = icd->dev.parent; | 1463 | struct device *dev = icd->dev.parent; |
1375 | __u32 pixfmt = pix->pixelformat; | 1464 | __u32 pixfmt = pix->pixelformat; |
@@ -1379,18 +1468,20 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1379 | unsigned int scale_cam_h, scale_cam_v; | 1468 | unsigned int scale_cam_h, scale_cam_v; |
1380 | u16 scale_v, scale_h; | 1469 | u16 scale_v, scale_h; |
1381 | int ret; | 1470 | int ret; |
1382 | bool is_interlaced, image_mode; | 1471 | bool image_mode; |
1472 | enum v4l2_field field; | ||
1383 | 1473 | ||
1384 | switch (pix->field) { | 1474 | switch (pix->field) { |
1385 | case V4L2_FIELD_INTERLACED: | ||
1386 | is_interlaced = true; | ||
1387 | break; | ||
1388 | case V4L2_FIELD_ANY: | ||
1389 | default: | 1475 | default: |
1390 | pix->field = V4L2_FIELD_NONE; | 1476 | pix->field = V4L2_FIELD_NONE; |
1391 | /* fall-through */ | 1477 | /* fall-through */ |
1478 | case V4L2_FIELD_INTERLACED_TB: | ||
1479 | case V4L2_FIELD_INTERLACED_BT: | ||
1392 | case V4L2_FIELD_NONE: | 1480 | case V4L2_FIELD_NONE: |
1393 | is_interlaced = false; | 1481 | field = pix->field; |
1482 | break; | ||
1483 | case V4L2_FIELD_INTERLACED: | ||
1484 | field = V4L2_FIELD_INTERLACED_TB; | ||
1394 | break; | 1485 | break; |
1395 | } | 1486 | } |
1396 | 1487 | ||
@@ -1438,9 +1529,11 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1438 | * 4. Calculate camera output window by applying combined scales to real | 1529 | * 4. Calculate camera output window by applying combined scales to real |
1439 | * input window. | 1530 | * input window. |
1440 | */ | 1531 | */ |
1441 | cam_pix->width = scale_down(cam_rect->width, scale_h); | 1532 | mf.width = scale_down(cam_rect->width, scale_h); |
1442 | cam_pix->height = scale_down(cam_rect->height, scale_v); | 1533 | mf.height = scale_down(cam_rect->height, scale_v); |
1443 | cam_pix->pixelformat = xlate->cam_fmt->fourcc; | 1534 | mf.field = pix->field; |
1535 | mf.colorspace = pix->colorspace; | ||
1536 | mf.code = xlate->code; | ||
1444 | 1537 | ||
1445 | switch (pixfmt) { | 1538 | switch (pixfmt) { |
1446 | case V4L2_PIX_FMT_NV12: | 1539 | case V4L2_PIX_FMT_NV12: |
@@ -1453,51 +1546,61 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1453 | image_mode = false; | 1546 | image_mode = false; |
1454 | } | 1547 | } |
1455 | 1548 | ||
1456 | dev_geo(dev, "4: camera output %ux%u\n", | 1549 | dev_geo(dev, "4: camera output %ux%u\n", mf.width, mf.height); |
1457 | cam_pix->width, cam_pix->height); | ||
1458 | 1550 | ||
1459 | /* 5. - 9. */ | 1551 | /* 5. - 9. */ |
1460 | ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f, | 1552 | ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &mf, |
1461 | image_mode && !is_interlaced); | 1553 | image_mode && V4L2_FIELD_NONE == field); |
1462 | 1554 | ||
1463 | dev_geo(dev, "5-9: client scale %d\n", ret); | 1555 | dev_geo(dev, "5-9: client scale %d\n", ret); |
1464 | 1556 | ||
1465 | /* Done with the camera. Now see if we can improve the result */ | 1557 | /* Done with the camera. Now see if we can improve the result */ |
1466 | 1558 | ||
1467 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", | 1559 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", |
1468 | ret, cam_pix->width, cam_pix->height, pix->width, pix->height); | 1560 | ret, mf.width, mf.height, pix->width, pix->height); |
1469 | if (ret < 0) | 1561 | if (ret < 0) |
1470 | return ret; | 1562 | return ret; |
1471 | 1563 | ||
1564 | if (mf.code != xlate->code) | ||
1565 | return -EINVAL; | ||
1566 | |||
1472 | /* 10. Use CEU scaling to scale to the requested user window. */ | 1567 | /* 10. Use CEU scaling to scale to the requested user window. */ |
1473 | 1568 | ||
1474 | /* We cannot scale up */ | 1569 | /* We cannot scale up */ |
1475 | if (pix->width > cam_pix->width) | 1570 | if (pix->width > mf.width) |
1476 | pix->width = cam_pix->width; | 1571 | pix->width = mf.width; |
1477 | if (pix->width > ceu_rect.width) | 1572 | if (pix->width > ceu_rect.width) |
1478 | pix->width = ceu_rect.width; | 1573 | pix->width = ceu_rect.width; |
1479 | 1574 | ||
1480 | if (pix->height > cam_pix->height) | 1575 | if (pix->height > mf.height) |
1481 | pix->height = cam_pix->height; | 1576 | pix->height = mf.height; |
1482 | if (pix->height > ceu_rect.height) | 1577 | if (pix->height > ceu_rect.height) |
1483 | pix->height = ceu_rect.height; | 1578 | pix->height = ceu_rect.height; |
1484 | 1579 | ||
1485 | /* Let's rock: scale pix->{width x height} down to width x height */ | 1580 | pix->colorspace = mf.colorspace; |
1486 | scale_h = calc_scale(ceu_rect.width, &pix->width); | 1581 | |
1487 | scale_v = calc_scale(ceu_rect.height, &pix->height); | 1582 | if (image_mode) { |
1583 | /* Scale pix->{width x height} down to width x height */ | ||
1584 | scale_h = calc_scale(ceu_rect.width, &pix->width); | ||
1585 | scale_v = calc_scale(ceu_rect.height, &pix->height); | ||
1586 | |||
1587 | pcdev->cflcr = scale_h | (scale_v << 16); | ||
1588 | } else { | ||
1589 | pix->width = ceu_rect.width; | ||
1590 | pix->height = ceu_rect.height; | ||
1591 | scale_h = scale_v = 0; | ||
1592 | pcdev->cflcr = 0; | ||
1593 | } | ||
1488 | 1594 | ||
1489 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", | 1595 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", |
1490 | ceu_rect.width, scale_h, pix->width, | 1596 | ceu_rect.width, scale_h, pix->width, |
1491 | ceu_rect.height, scale_v, pix->height); | 1597 | ceu_rect.height, scale_v, pix->height); |
1492 | 1598 | ||
1493 | pcdev->cflcr = scale_h | (scale_v << 16); | 1599 | cam->code = xlate->code; |
1600 | cam->ceu_rect = ceu_rect; | ||
1601 | icd->current_fmt = xlate; | ||
1494 | 1602 | ||
1495 | icd->buswidth = xlate->buswidth; | 1603 | pcdev->field = field; |
1496 | icd->current_fmt = xlate->host_fmt; | ||
1497 | cam->camera_fmt = xlate->cam_fmt; | ||
1498 | cam->ceu_rect = ceu_rect; | ||
1499 | |||
1500 | pcdev->is_interlaced = is_interlaced; | ||
1501 | pcdev->image_mode = image_mode; | 1604 | pcdev->image_mode = image_mode; |
1502 | 1605 | ||
1503 | return 0; | 1606 | return 0; |
@@ -1509,6 +1612,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1509 | const struct soc_camera_format_xlate *xlate; | 1612 | const struct soc_camera_format_xlate *xlate; |
1510 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1613 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1511 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1614 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1615 | struct v4l2_mbus_framefmt mf; | ||
1512 | __u32 pixfmt = pix->pixelformat; | 1616 | __u32 pixfmt = pix->pixelformat; |
1513 | int width, height; | 1617 | int width, height; |
1514 | int ret; | 1618 | int ret; |
@@ -1527,18 +1631,27 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1527 | width = pix->width; | 1631 | width = pix->width; |
1528 | height = pix->height; | 1632 | height = pix->height; |
1529 | 1633 | ||
1530 | pix->bytesperline = pix->width * | 1634 | pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt); |
1531 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 1635 | if (pix->bytesperline < 0) |
1532 | pix->sizeimage = pix->height * pix->bytesperline; | 1636 | return pix->bytesperline; |
1533 | 1637 | pix->sizeimage = height * pix->bytesperline; | |
1534 | pix->pixelformat = xlate->cam_fmt->fourcc; | ||
1535 | 1638 | ||
1536 | /* limit to sensor capabilities */ | 1639 | /* limit to sensor capabilities */ |
1537 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 1640 | mf.width = pix->width; |
1538 | pix->pixelformat = pixfmt; | 1641 | mf.height = pix->height; |
1642 | mf.field = pix->field; | ||
1643 | mf.code = xlate->code; | ||
1644 | mf.colorspace = pix->colorspace; | ||
1645 | |||
1646 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1539 | if (ret < 0) | 1647 | if (ret < 0) |
1540 | return ret; | 1648 | return ret; |
1541 | 1649 | ||
1650 | pix->width = mf.width; | ||
1651 | pix->height = mf.height; | ||
1652 | pix->field = mf.field; | ||
1653 | pix->colorspace = mf.colorspace; | ||
1654 | |||
1542 | switch (pixfmt) { | 1655 | switch (pixfmt) { |
1543 | case V4L2_PIX_FMT_NV12: | 1656 | case V4L2_PIX_FMT_NV12: |
1544 | case V4L2_PIX_FMT_NV21: | 1657 | case V4L2_PIX_FMT_NV21: |
@@ -1547,21 +1660,25 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1547 | /* FIXME: check against rect_max after converting soc-camera */ | 1660 | /* FIXME: check against rect_max after converting soc-camera */ |
1548 | /* We can scale precisely, need a bigger image from camera */ | 1661 | /* We can scale precisely, need a bigger image from camera */ |
1549 | if (pix->width < width || pix->height < height) { | 1662 | if (pix->width < width || pix->height < height) { |
1550 | int tmp_w = pix->width, tmp_h = pix->height; | 1663 | /* |
1551 | pix->width = 2560; | 1664 | * We presume, the sensor behaves sanely, i.e., if |
1552 | pix->height = 1920; | 1665 | * requested a bigger rectangle, it will not return a |
1553 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 1666 | * smaller one. |
1667 | */ | ||
1668 | mf.width = 2560; | ||
1669 | mf.height = 1920; | ||
1670 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1554 | if (ret < 0) { | 1671 | if (ret < 0) { |
1555 | /* Shouldn't actually happen... */ | 1672 | /* Shouldn't actually happen... */ |
1556 | dev_err(icd->dev.parent, | 1673 | dev_err(icd->dev.parent, |
1557 | "FIXME: try_fmt() returned %d\n", ret); | 1674 | "FIXME: client try_fmt() = %d\n", ret); |
1558 | pix->width = tmp_w; | 1675 | return ret; |
1559 | pix->height = tmp_h; | ||
1560 | } | 1676 | } |
1561 | } | 1677 | } |
1562 | if (pix->width > width) | 1678 | /* We will scale exactly */ |
1679 | if (mf.width > width) | ||
1563 | pix->width = width; | 1680 | pix->width = width; |
1564 | if (pix->height > height) | 1681 | if (mf.height > height) |
1565 | pix->height = height; | 1682 | pix->height = height; |
1566 | } | 1683 | } |
1567 | 1684 | ||
@@ -1573,10 +1690,12 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, | |||
1573 | { | 1690 | { |
1574 | int i; | 1691 | int i; |
1575 | 1692 | ||
1576 | /* This is for locking debugging only. I removed spinlocks and now I | 1693 | /* |
1694 | * This is for locking debugging only. I removed spinlocks and now I | ||
1577 | * check whether .prepare is ever called on a linked buffer, or whether | 1695 | * check whether .prepare is ever called on a linked buffer, or whether |
1578 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | 1696 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now |
1579 | * it hadn't triggered */ | 1697 | * it hadn't triggered |
1698 | */ | ||
1580 | for (i = 0; i < p->count; i++) { | 1699 | for (i = 0; i < p->count; i++) { |
1581 | struct sh_mobile_ceu_buffer *buf; | 1700 | struct sh_mobile_ceu_buffer *buf; |
1582 | 1701 | ||
@@ -1624,8 +1743,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, | |||
1624 | &sh_mobile_ceu_videobuf_ops, | 1743 | &sh_mobile_ceu_videobuf_ops, |
1625 | icd->dev.parent, &pcdev->lock, | 1744 | icd->dev.parent, &pcdev->lock, |
1626 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 1745 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
1627 | pcdev->is_interlaced ? | 1746 | pcdev->field, |
1628 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, | ||
1629 | sizeof(struct sh_mobile_ceu_buffer), | 1747 | sizeof(struct sh_mobile_ceu_buffer), |
1630 | icd); | 1748 | icd); |
1631 | } | 1749 | } |
@@ -1654,7 +1772,7 @@ static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, | |||
1654 | 1772 | ||
1655 | switch (ctrl->id) { | 1773 | switch (ctrl->id) { |
1656 | case V4L2_CID_SHARPNESS: | 1774 | case V4L2_CID_SHARPNESS: |
1657 | switch (icd->current_fmt->fourcc) { | 1775 | switch (icd->current_fmt->host_fmt->fourcc) { |
1658 | case V4L2_PIX_FMT_NV12: | 1776 | case V4L2_PIX_FMT_NV12: |
1659 | case V4L2_PIX_FMT_NV21: | 1777 | case V4L2_PIX_FMT_NV21: |
1660 | case V4L2_PIX_FMT_NV16: | 1778 | case V4L2_PIX_FMT_NV16: |
@@ -1836,7 +1954,7 @@ static struct platform_driver sh_mobile_ceu_driver = { | |||
1836 | .pm = &sh_mobile_ceu_dev_pm_ops, | 1954 | .pm = &sh_mobile_ceu_dev_pm_ops, |
1837 | }, | 1955 | }, |
1838 | .probe = sh_mobile_ceu_probe, | 1956 | .probe = sh_mobile_ceu_probe, |
1839 | .remove = __exit_p(sh_mobile_ceu_remove), | 1957 | .remove = __devexit_p(sh_mobile_ceu_remove), |
1840 | }; | 1958 | }; |
1841 | 1959 | ||
1842 | static int __init sh_mobile_ceu_init(void) | 1960 | static int __init sh_mobile_ceu_init(void) |
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 4a7711c3e745..cbf8087b286f 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -1007,8 +1007,8 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam) | |||
1007 | else if (cam->stream != STREAM_OFF) { | 1007 | else if (cam->stream != STREAM_OFF) { |
1008 | cam->state |= DEV_MISCONFIGURED; | 1008 | cam->state |= DEV_MISCONFIGURED; |
1009 | DBG(1, "URB timeout reached. The camera is misconfigured. " | 1009 | DBG(1, "URB timeout reached. The camera is misconfigured. " |
1010 | "To use it, close and open /dev/video%d again.", | 1010 | "To use it, close and open %s again.", |
1011 | cam->v4ldev->num); | 1011 | video_device_node_name(cam->v4ldev)); |
1012 | return -EIO; | 1012 | return -EIO; |
1013 | } | 1013 | } |
1014 | 1014 | ||
@@ -1734,7 +1734,8 @@ static void sn9c102_release_resources(struct kref *kref) | |||
1734 | 1734 | ||
1735 | cam = container_of(kref, struct sn9c102_device, kref); | 1735 | cam = container_of(kref, struct sn9c102_device, kref); |
1736 | 1736 | ||
1737 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); | 1737 | DBG(2, "V4L2 device %s deregistered", |
1738 | video_device_node_name(cam->v4ldev)); | ||
1738 | video_set_drvdata(cam->v4ldev, NULL); | 1739 | video_set_drvdata(cam->v4ldev, NULL); |
1739 | video_unregister_device(cam->v4ldev); | 1740 | video_unregister_device(cam->v4ldev); |
1740 | usb_put_dev(cam->usbdev); | 1741 | usb_put_dev(cam->usbdev); |
@@ -1791,8 +1792,8 @@ static int sn9c102_open(struct file *filp) | |||
1791 | } | 1792 | } |
1792 | 1793 | ||
1793 | if (cam->users) { | 1794 | if (cam->users) { |
1794 | DBG(2, "Device /dev/video%d is already in use", | 1795 | DBG(2, "Device %s is already in use", |
1795 | cam->v4ldev->num); | 1796 | video_device_node_name(cam->v4ldev)); |
1796 | DBG(3, "Simultaneous opens are not supported"); | 1797 | DBG(3, "Simultaneous opens are not supported"); |
1797 | /* | 1798 | /* |
1798 | open() must follow the open flags and should block | 1799 | open() must follow the open flags and should block |
@@ -1845,7 +1846,7 @@ static int sn9c102_open(struct file *filp) | |||
1845 | cam->frame_count = 0; | 1846 | cam->frame_count = 0; |
1846 | sn9c102_empty_framequeues(cam); | 1847 | sn9c102_empty_framequeues(cam); |
1847 | 1848 | ||
1848 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); | 1849 | DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev)); |
1849 | 1850 | ||
1850 | out: | 1851 | out: |
1851 | mutex_unlock(&cam->open_mutex); | 1852 | mutex_unlock(&cam->open_mutex); |
@@ -1870,7 +1871,7 @@ static int sn9c102_release(struct file *filp) | |||
1870 | cam->users--; | 1871 | cam->users--; |
1871 | wake_up_interruptible_nr(&cam->wait_open, 1); | 1872 | wake_up_interruptible_nr(&cam->wait_open, 1); |
1872 | 1873 | ||
1873 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); | 1874 | DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev)); |
1874 | 1875 | ||
1875 | kref_put(&cam->kref, sn9c102_release_resources); | 1876 | kref_put(&cam->kref, sn9c102_release_resources); |
1876 | 1877 | ||
@@ -2433,8 +2434,8 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | |||
2433 | if (err) { /* atomic, no rollback in ioctl() */ | 2434 | if (err) { /* atomic, no rollback in ioctl() */ |
2434 | cam->state |= DEV_MISCONFIGURED; | 2435 | cam->state |= DEV_MISCONFIGURED; |
2435 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | 2436 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " |
2436 | "use the camera, close and open /dev/video%d again.", | 2437 | "use the camera, close and open %s again.", |
2437 | cam->v4ldev->num); | 2438 | video_device_node_name(cam->v4ldev)); |
2438 | return -EIO; | 2439 | return -EIO; |
2439 | } | 2440 | } |
2440 | 2441 | ||
@@ -2446,8 +2447,8 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | |||
2446 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | 2447 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { |
2447 | cam->state |= DEV_MISCONFIGURED; | 2448 | cam->state |= DEV_MISCONFIGURED; |
2448 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | 2449 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " |
2449 | "use the camera, close and open /dev/video%d again.", | 2450 | "use the camera, close and open %s again.", |
2450 | cam->v4ldev->num); | 2451 | video_device_node_name(cam->v4ldev)); |
2451 | return -ENOMEM; | 2452 | return -ENOMEM; |
2452 | } | 2453 | } |
2453 | 2454 | ||
@@ -2690,8 +2691,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2690 | if (err) { /* atomic, no rollback in ioctl() */ | 2691 | if (err) { /* atomic, no rollback in ioctl() */ |
2691 | cam->state |= DEV_MISCONFIGURED; | 2692 | cam->state |= DEV_MISCONFIGURED; |
2692 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | 2693 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " |
2693 | "use the camera, close and open /dev/video%d again.", | 2694 | "use the camera, close and open %s again.", |
2694 | cam->v4ldev->num); | 2695 | video_device_node_name(cam->v4ldev)); |
2695 | return -EIO; | 2696 | return -EIO; |
2696 | } | 2697 | } |
2697 | 2698 | ||
@@ -2702,8 +2703,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2702 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | 2703 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { |
2703 | cam->state |= DEV_MISCONFIGURED; | 2704 | cam->state |= DEV_MISCONFIGURED; |
2704 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | 2705 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " |
2705 | "use the camera, close and open /dev/video%d again.", | 2706 | "use the camera, close and open %s again.", |
2706 | cam->v4ldev->num); | 2707 | video_device_node_name(cam->v4ldev)); |
2707 | return -ENOMEM; | 2708 | return -ENOMEM; |
2708 | } | 2709 | } |
2709 | 2710 | ||
@@ -2748,9 +2749,9 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) | |||
2748 | err += sn9c102_set_compression(cam, &jc); | 2749 | err += sn9c102_set_compression(cam, &jc); |
2749 | if (err) { /* atomic, no rollback in ioctl() */ | 2750 | if (err) { /* atomic, no rollback in ioctl() */ |
2750 | cam->state |= DEV_MISCONFIGURED; | 2751 | cam->state |= DEV_MISCONFIGURED; |
2751 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | 2752 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. " |
2752 | "problems. To use the camera, close and open " | 2753 | "To use the camera, close and open %s again.", |
2753 | "/dev/video%d again.", cam->v4ldev->num); | 2754 | video_device_node_name(cam->v4ldev)); |
2754 | return -EIO; | 2755 | return -EIO; |
2755 | } | 2756 | } |
2756 | 2757 | ||
@@ -3328,7 +3329,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3328 | 3329 | ||
3329 | strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); | 3330 | strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); |
3330 | cam->v4ldev->fops = &sn9c102_fops; | 3331 | cam->v4ldev->fops = &sn9c102_fops; |
3331 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
3332 | cam->v4ldev->release = video_device_release; | 3332 | cam->v4ldev->release = video_device_release; |
3333 | cam->v4ldev->parent = &udev->dev; | 3333 | cam->v4ldev->parent = &udev->dev; |
3334 | 3334 | ||
@@ -3346,7 +3346,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3346 | goto fail; | 3346 | goto fail; |
3347 | } | 3347 | } |
3348 | 3348 | ||
3349 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); | 3349 | DBG(2, "V4L2 device registered as %s", |
3350 | video_device_node_name(cam->v4ldev)); | ||
3350 | 3351 | ||
3351 | video_set_drvdata(cam->v4ldev, cam); | 3352 | video_set_drvdata(cam->v4ldev, cam); |
3352 | cam->module_param.force_munmap = force_munmap[dev_nr]; | 3353 | cam->module_param.force_munmap = force_munmap[dev_nr]; |
@@ -3398,9 +3399,9 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) | |||
3398 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | 3399 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); |
3399 | 3400 | ||
3400 | if (cam->users) { | 3401 | if (cam->users) { |
3401 | DBG(2, "Device /dev/video%d is open! Deregistration and " | 3402 | DBG(2, "Device %s is open! Deregistration and memory " |
3402 | "memory deallocation are deferred.", | 3403 | "deallocation are deferred.", |
3403 | cam->v4ldev->num); | 3404 | video_device_node_name(cam->v4ldev)); |
3404 | cam->state |= DEV_MISCONFIGURED; | 3405 | cam->state |= DEV_MISCONFIGURED; |
3405 | sn9c102_stop_transfer(cam); | 3406 | sn9c102_stop_transfer(cam); |
3406 | cam->state |= DEV_DISCONNECTED; | 3407 | cam->state |= DEV_DISCONNECTED; |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 95fdeb23c2c1..6b3fbcca7747 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
32 | #include <media/v4l2-dev.h> | 32 | #include <media/v4l2-dev.h> |
33 | #include <media/videobuf-core.h> | 33 | #include <media/videobuf-core.h> |
34 | #include <media/soc_mediabus.h> | ||
34 | 35 | ||
35 | /* Default to VGA resolution */ | 36 | /* Default to VGA resolution */ |
36 | #define DEFAULT_WIDTH 640 | 37 | #define DEFAULT_WIDTH 640 |
@@ -40,18 +41,6 @@ static LIST_HEAD(hosts); | |||
40 | static LIST_HEAD(devices); | 41 | static LIST_HEAD(devices); |
41 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 42 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
42 | 43 | ||
43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | ||
44 | struct soc_camera_device *icd, unsigned int fourcc) | ||
45 | { | ||
46 | unsigned int i; | ||
47 | |||
48 | for (i = 0; i < icd->num_formats; i++) | ||
49 | if (icd->formats[i].fourcc == fourcc) | ||
50 | return icd->formats + i; | ||
51 | return NULL; | ||
52 | } | ||
53 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); | ||
54 | |||
55 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 44 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
56 | struct soc_camera_device *icd, unsigned int fourcc) | 45 | struct soc_camera_device *icd, unsigned int fourcc) |
57 | { | 46 | { |
@@ -207,21 +196,26 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
207 | /* Always entered with .video_lock held */ | 196 | /* Always entered with .video_lock held */ |
208 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 197 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
209 | { | 198 | { |
199 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
210 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 200 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
211 | int i, fmts = 0, ret; | 201 | int i, fmts = 0, raw_fmts = 0, ret; |
202 | enum v4l2_mbus_pixelcode code; | ||
203 | |||
204 | while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) | ||
205 | raw_fmts++; | ||
212 | 206 | ||
213 | if (!ici->ops->get_formats) | 207 | if (!ici->ops->get_formats) |
214 | /* | 208 | /* |
215 | * Fallback mode - the host will have to serve all | 209 | * Fallback mode - the host will have to serve all |
216 | * sensor-provided formats one-to-one to the user | 210 | * sensor-provided formats one-to-one to the user |
217 | */ | 211 | */ |
218 | fmts = icd->num_formats; | 212 | fmts = raw_fmts; |
219 | else | 213 | else |
220 | /* | 214 | /* |
221 | * First pass - only count formats this host-sensor | 215 | * First pass - only count formats this host-sensor |
222 | * configuration can provide | 216 | * configuration can provide |
223 | */ | 217 | */ |
224 | for (i = 0; i < icd->num_formats; i++) { | 218 | for (i = 0; i < raw_fmts; i++) { |
225 | ret = ici->ops->get_formats(icd, i, NULL); | 219 | ret = ici->ops->get_formats(icd, i, NULL); |
226 | if (ret < 0) | 220 | if (ret < 0) |
227 | return ret; | 221 | return ret; |
@@ -242,11 +236,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
242 | 236 | ||
243 | /* Second pass - actually fill data formats */ | 237 | /* Second pass - actually fill data formats */ |
244 | fmts = 0; | 238 | fmts = 0; |
245 | for (i = 0; i < icd->num_formats; i++) | 239 | for (i = 0; i < raw_fmts; i++) |
246 | if (!ici->ops->get_formats) { | 240 | if (!ici->ops->get_formats) { |
247 | icd->user_formats[i].host_fmt = icd->formats + i; | 241 | v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); |
248 | icd->user_formats[i].cam_fmt = icd->formats + i; | 242 | icd->user_formats[i].host_fmt = |
249 | icd->user_formats[i].buswidth = icd->formats[i].depth; | 243 | soc_mbus_get_fmtdesc(code); |
244 | icd->user_formats[i].code = code; | ||
250 | } else { | 245 | } else { |
251 | ret = ici->ops->get_formats(icd, i, | 246 | ret = ici->ops->get_formats(icd, i, |
252 | &icd->user_formats[fmts]); | 247 | &icd->user_formats[fmts]); |
@@ -255,7 +250,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
255 | fmts += ret; | 250 | fmts += ret; |
256 | } | 251 | } |
257 | 252 | ||
258 | icd->current_fmt = icd->user_formats[0].host_fmt; | 253 | icd->current_fmt = &icd->user_formats[0]; |
259 | 254 | ||
260 | return 0; | 255 | return 0; |
261 | 256 | ||
@@ -281,7 +276,7 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) | |||
281 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | 276 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ |
282 | ((x) >> 24) & 0xff | 277 | ((x) >> 24) & 0xff |
283 | 278 | ||
284 | /* Called with .vb_lock held */ | 279 | /* Called with .vb_lock held, or from the first open(2), see comment there */ |
285 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | 280 | static int soc_camera_set_fmt(struct soc_camera_file *icf, |
286 | struct v4l2_format *f) | 281 | struct v4l2_format *f) |
287 | { | 282 | { |
@@ -302,7 +297,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
302 | if (ret < 0) { | 297 | if (ret < 0) { |
303 | return ret; | 298 | return ret; |
304 | } else if (!icd->current_fmt || | 299 | } else if (!icd->current_fmt || |
305 | icd->current_fmt->fourcc != pix->pixelformat) { | 300 | icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { |
306 | dev_err(&icd->dev, | 301 | dev_err(&icd->dev, |
307 | "Host driver hasn't set up current format correctly!\n"); | 302 | "Host driver hasn't set up current format correctly!\n"); |
308 | return -EINVAL; | 303 | return -EINVAL; |
@@ -310,6 +305,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, | |||
310 | 305 | ||
311 | icd->user_width = pix->width; | 306 | icd->user_width = pix->width; |
312 | icd->user_height = pix->height; | 307 | icd->user_height = pix->height; |
308 | icd->colorspace = pix->colorspace; | ||
313 | icf->vb_vidq.field = | 309 | icf->vb_vidq.field = |
314 | icd->field = pix->field; | 310 | icd->field = pix->field; |
315 | 311 | ||
@@ -369,8 +365,9 @@ static int soc_camera_open(struct file *file) | |||
369 | .width = icd->user_width, | 365 | .width = icd->user_width, |
370 | .height = icd->user_height, | 366 | .height = icd->user_height, |
371 | .field = icd->field, | 367 | .field = icd->field, |
372 | .pixelformat = icd->current_fmt->fourcc, | 368 | .colorspace = icd->colorspace, |
373 | .colorspace = icd->current_fmt->colorspace, | 369 | .pixelformat = |
370 | icd->current_fmt->host_fmt->fourcc, | ||
374 | }, | 371 | }, |
375 | }; | 372 | }; |
376 | 373 | ||
@@ -390,7 +387,12 @@ static int soc_camera_open(struct file *file) | |||
390 | goto eiciadd; | 387 | goto eiciadd; |
391 | } | 388 | } |
392 | 389 | ||
393 | /* Try to configure with default parameters */ | 390 | /* |
391 | * Try to configure with default parameters. Notice: this is the | ||
392 | * very first open, so, we cannot race against other calls, | ||
393 | * apart from someone else calling open() simultaneously, but | ||
394 | * .video_lock is protecting us against it. | ||
395 | */ | ||
394 | ret = soc_camera_set_fmt(icf, &f); | 396 | ret = soc_camera_set_fmt(icf, &f); |
395 | if (ret < 0) | 397 | if (ret < 0) |
396 | goto esfmt; | 398 | goto esfmt; |
@@ -534,7 +536,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
534 | { | 536 | { |
535 | struct soc_camera_file *icf = file->private_data; | 537 | struct soc_camera_file *icf = file->private_data; |
536 | struct soc_camera_device *icd = icf->icd; | 538 | struct soc_camera_device *icd = icf->icd; |
537 | const struct soc_camera_data_format *format; | 539 | const struct soc_mbus_pixelfmt *format; |
538 | 540 | ||
539 | WARN_ON(priv != file->private_data); | 541 | WARN_ON(priv != file->private_data); |
540 | 542 | ||
@@ -543,7 +545,8 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | |||
543 | 545 | ||
544 | format = icd->user_formats[f->index].host_fmt; | 546 | format = icd->user_formats[f->index].host_fmt; |
545 | 547 | ||
546 | strlcpy(f->description, format->name, sizeof(f->description)); | 548 | if (format->name) |
549 | strlcpy(f->description, format->name, sizeof(f->description)); | ||
547 | f->pixelformat = format->fourcc; | 550 | f->pixelformat = format->fourcc; |
548 | return 0; | 551 | return 0; |
549 | } | 552 | } |
@@ -560,12 +563,15 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, | |||
560 | pix->width = icd->user_width; | 563 | pix->width = icd->user_width; |
561 | pix->height = icd->user_height; | 564 | pix->height = icd->user_height; |
562 | pix->field = icf->vb_vidq.field; | 565 | pix->field = icf->vb_vidq.field; |
563 | pix->pixelformat = icd->current_fmt->fourcc; | 566 | pix->pixelformat = icd->current_fmt->host_fmt->fourcc; |
564 | pix->bytesperline = pix->width * | 567 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, |
565 | DIV_ROUND_UP(icd->current_fmt->depth, 8); | 568 | icd->current_fmt->host_fmt); |
569 | pix->colorspace = icd->colorspace; | ||
570 | if (pix->bytesperline < 0) | ||
571 | return pix->bytesperline; | ||
566 | pix->sizeimage = pix->height * pix->bytesperline; | 572 | pix->sizeimage = pix->height * pix->bytesperline; |
567 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", | 573 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", |
568 | icd->current_fmt->fourcc); | 574 | icd->current_fmt->host_fmt->fourcc); |
569 | return 0; | 575 | return 0; |
570 | } | 576 | } |
571 | 577 | ||
@@ -621,8 +627,10 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
621 | 627 | ||
622 | mutex_lock(&icd->video_lock); | 628 | mutex_lock(&icd->video_lock); |
623 | 629 | ||
624 | /* This calls buf_release from host driver's videobuf_queue_ops for all | 630 | /* |
625 | * remaining buffers. When the last buffer is freed, stop capture */ | 631 | * This calls buf_release from host driver's videobuf_queue_ops for all |
632 | * remaining buffers. When the last buffer is freed, stop capture | ||
633 | */ | ||
626 | videobuf_streamoff(&icf->vb_vidq); | 634 | videobuf_streamoff(&icf->vb_vidq); |
627 | 635 | ||
628 | v4l2_subdev_call(sd, video, s_stream, 0); | 636 | v4l2_subdev_call(sd, video, s_stream, 0); |
@@ -892,7 +900,7 @@ static int soc_camera_probe(struct device *dev) | |||
892 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 900 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
893 | struct device *control = NULL; | 901 | struct device *control = NULL; |
894 | struct v4l2_subdev *sd; | 902 | struct v4l2_subdev *sd; |
895 | struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; | 903 | struct v4l2_mbus_framefmt mf; |
896 | int ret; | 904 | int ret; |
897 | 905 | ||
898 | dev_info(dev, "Probing %s\n", dev_name(dev)); | 906 | dev_info(dev, "Probing %s\n", dev_name(dev)); |
@@ -963,9 +971,11 @@ static int soc_camera_probe(struct device *dev) | |||
963 | 971 | ||
964 | /* Try to improve our guess of a reasonable window format */ | 972 | /* Try to improve our guess of a reasonable window format */ |
965 | sd = soc_camera_to_subdev(icd); | 973 | sd = soc_camera_to_subdev(icd); |
966 | if (!v4l2_subdev_call(sd, video, g_fmt, &f)) { | 974 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { |
967 | icd->user_width = f.fmt.pix.width; | 975 | icd->user_width = mf.width; |
968 | icd->user_height = f.fmt.pix.height; | 976 | icd->user_height = mf.height; |
977 | icd->colorspace = mf.colorspace; | ||
978 | icd->field = mf.field; | ||
969 | } | 979 | } |
970 | 980 | ||
971 | /* Do we have to sysfs_remove_link() before device_unregister()? */ | 981 | /* Do we have to sysfs_remove_link() before device_unregister()? */ |
@@ -1004,8 +1014,10 @@ epower: | |||
1004 | return ret; | 1014 | return ret; |
1005 | } | 1015 | } |
1006 | 1016 | ||
1007 | /* This is called on device_unregister, which only means we have to disconnect | 1017 | /* |
1008 | * from the host, but not remove ourselves from the device list */ | 1018 | * This is called on device_unregister, which only means we have to disconnect |
1019 | * from the host, but not remove ourselves from the device list | ||
1020 | */ | ||
1009 | static int soc_camera_remove(struct device *dev) | 1021 | static int soc_camera_remove(struct device *dev) |
1010 | { | 1022 | { |
1011 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 1023 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
@@ -1205,8 +1217,10 @@ static int soc_camera_device_register(struct soc_camera_device *icd) | |||
1205 | } | 1217 | } |
1206 | 1218 | ||
1207 | if (num < 0) | 1219 | if (num < 0) |
1208 | /* ok, we have 256 cameras on this host... | 1220 | /* |
1209 | * man, stay reasonable... */ | 1221 | * ok, we have 256 cameras on this host... |
1222 | * man, stay reasonable... | ||
1223 | */ | ||
1210 | return -ENOMEM; | 1224 | return -ENOMEM; |
1211 | 1225 | ||
1212 | icd->devnum = num; | 1226 | icd->devnum = num; |
@@ -1268,7 +1282,6 @@ static int video_dev_create(struct soc_camera_device *icd) | |||
1268 | vdev->fops = &soc_camera_fops; | 1282 | vdev->fops = &soc_camera_fops; |
1269 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | 1283 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
1270 | vdev->release = video_device_release; | 1284 | vdev->release = video_device_release; |
1271 | vdev->minor = -1; | ||
1272 | vdev->tvnorms = V4L2_STD_UNKNOWN; | 1285 | vdev->tvnorms = V4L2_STD_UNKNOWN; |
1273 | 1286 | ||
1274 | icd->vdev = vdev; | 1287 | icd->vdev = vdev; |
@@ -1291,8 +1304,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd) | |||
1291 | !icd->ops->set_bus_param) | 1304 | !icd->ops->set_bus_param) |
1292 | return -EINVAL; | 1305 | return -EINVAL; |
1293 | 1306 | ||
1294 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, | 1307 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); |
1295 | icd->vdev->minor); | ||
1296 | if (ret < 0) { | 1308 | if (ret < 0) { |
1297 | dev_err(&icd->dev, "video_register_device failed: %d\n", ret); | 1309 | dev_err(&icd->dev, "video_register_device failed: %d\n", ret); |
1298 | return ret; | 1310 | return ret; |
@@ -1335,9 +1347,11 @@ escdevreg: | |||
1335 | return ret; | 1347 | return ret; |
1336 | } | 1348 | } |
1337 | 1349 | ||
1338 | /* Only called on rmmod for each platform device, since they are not | 1350 | /* |
1351 | * Only called on rmmod for each platform device, since they are not | ||
1339 | * hot-pluggable. Now we know, that all our users - hosts and devices have | 1352 | * hot-pluggable. Now we know, that all our users - hosts and devices have |
1340 | * been unloaded already */ | 1353 | * been unloaded already |
1354 | */ | ||
1341 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | 1355 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) |
1342 | { | 1356 | { |
1343 | struct soc_camera_device *icd = platform_get_drvdata(pdev); | 1357 | struct soc_camera_device *icd = platform_get_drvdata(pdev); |
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index b6a575ce5da2..10b003a8be83 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
@@ -22,7 +22,6 @@ | |||
22 | 22 | ||
23 | struct soc_camera_platform_priv { | 23 | struct soc_camera_platform_priv { |
24 | struct v4l2_subdev subdev; | 24 | struct v4l2_subdev subdev; |
25 | struct soc_camera_data_format format; | ||
26 | }; | 25 | }; |
27 | 26 | ||
28 | static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) | 27 | static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) |
@@ -58,36 +57,36 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd) | |||
58 | } | 57 | } |
59 | 58 | ||
60 | static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, | 59 | static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, |
61 | struct v4l2_format *f) | 60 | struct v4l2_mbus_framefmt *mf) |
62 | { | 61 | { |
63 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | 62 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
64 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
65 | 63 | ||
66 | pix->width = p->format.width; | 64 | mf->width = p->format.width; |
67 | pix->height = p->format.height; | 65 | mf->height = p->format.height; |
66 | mf->code = p->format.code; | ||
67 | mf->colorspace = p->format.colorspace; | ||
68 | |||
68 | return 0; | 69 | return 0; |
69 | } | 70 | } |
70 | 71 | ||
71 | static void soc_camera_platform_video_probe(struct soc_camera_device *icd, | 72 | static struct v4l2_subdev_core_ops platform_subdev_core_ops; |
72 | struct platform_device *pdev) | 73 | |
74 | static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index, | ||
75 | enum v4l2_mbus_pixelcode *code) | ||
73 | { | 76 | { |
74 | struct soc_camera_platform_priv *priv = get_priv(pdev); | 77 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
75 | struct soc_camera_platform_info *p = pdev->dev.platform_data; | ||
76 | 78 | ||
77 | priv->format.name = p->format_name; | 79 | if (index) |
78 | priv->format.depth = p->format_depth; | 80 | return -EINVAL; |
79 | priv->format.fourcc = p->format.pixelformat; | ||
80 | priv->format.colorspace = p->format.colorspace; | ||
81 | 81 | ||
82 | icd->formats = &priv->format; | 82 | *code = p->format.code; |
83 | icd->num_formats = 1; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static struct v4l2_subdev_core_ops platform_subdev_core_ops; | ||
87 | |||
88 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | 86 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { |
89 | .s_stream = soc_camera_platform_s_stream, | 87 | .s_stream = soc_camera_platform_s_stream, |
90 | .try_fmt = soc_camera_platform_try_fmt, | 88 | .try_mbus_fmt = soc_camera_platform_try_fmt, |
89 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, | ||
91 | }; | 90 | }; |
92 | 91 | ||
93 | static struct v4l2_subdev_ops platform_subdev_ops = { | 92 | static struct v4l2_subdev_ops platform_subdev_ops = { |
@@ -128,13 +127,10 @@ static int soc_camera_platform_probe(struct platform_device *pdev) | |||
128 | /* Set the control device reference */ | 127 | /* Set the control device reference */ |
129 | dev_set_drvdata(&icd->dev, &pdev->dev); | 128 | dev_set_drvdata(&icd->dev, &pdev->dev); |
130 | 129 | ||
131 | icd->y_skip_top = 0; | 130 | icd->ops = &soc_camera_platform_ops; |
132 | icd->ops = &soc_camera_platform_ops; | ||
133 | 131 | ||
134 | ici = to_soc_camera_host(icd->dev.parent); | 132 | ici = to_soc_camera_host(icd->dev.parent); |
135 | 133 | ||
136 | soc_camera_platform_video_probe(icd, pdev); | ||
137 | |||
138 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); | 134 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); |
139 | v4l2_set_subdevdata(&priv->subdev, p); | 135 | v4l2_set_subdevdata(&priv->subdev, p); |
140 | strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); | 136 | strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); |
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c new file mode 100644 index 000000000000..f8d5c87dc2aa --- /dev/null +++ b/drivers/media/video/soc_mediabus.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * soc-camera media bus helper routines | ||
3 | * | ||
4 | * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include <media/v4l2-device.h> | ||
15 | #include <media/v4l2-mediabus.h> | ||
16 | #include <media/soc_mediabus.h> | ||
17 | |||
18 | #define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1) | ||
19 | |||
20 | static const struct soc_mbus_pixelfmt mbus_fmt[] = { | ||
21 | [MBUS_IDX(YUYV8_2X8_LE)] = { | ||
22 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
23 | .name = "YUYV", | ||
24 | .bits_per_sample = 8, | ||
25 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
26 | .order = SOC_MBUS_ORDER_LE, | ||
27 | }, [MBUS_IDX(YVYU8_2X8_LE)] = { | ||
28 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
29 | .name = "YVYU", | ||
30 | .bits_per_sample = 8, | ||
31 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
32 | .order = SOC_MBUS_ORDER_LE, | ||
33 | }, [MBUS_IDX(YUYV8_2X8_BE)] = { | ||
34 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
35 | .name = "UYVY", | ||
36 | .bits_per_sample = 8, | ||
37 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
38 | .order = SOC_MBUS_ORDER_LE, | ||
39 | }, [MBUS_IDX(YVYU8_2X8_BE)] = { | ||
40 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
41 | .name = "VYUY", | ||
42 | .bits_per_sample = 8, | ||
43 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
44 | .order = SOC_MBUS_ORDER_LE, | ||
45 | }, [MBUS_IDX(RGB555_2X8_PADHI_LE)] = { | ||
46 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
47 | .name = "RGB555", | ||
48 | .bits_per_sample = 8, | ||
49 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
50 | .order = SOC_MBUS_ORDER_LE, | ||
51 | }, [MBUS_IDX(RGB555_2X8_PADHI_BE)] = { | ||
52 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
53 | .name = "RGB555X", | ||
54 | .bits_per_sample = 8, | ||
55 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
56 | .order = SOC_MBUS_ORDER_LE, | ||
57 | }, [MBUS_IDX(RGB565_2X8_LE)] = { | ||
58 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
59 | .name = "RGB565", | ||
60 | .bits_per_sample = 8, | ||
61 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
62 | .order = SOC_MBUS_ORDER_LE, | ||
63 | }, [MBUS_IDX(RGB565_2X8_BE)] = { | ||
64 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
65 | .name = "RGB565X", | ||
66 | .bits_per_sample = 8, | ||
67 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
68 | .order = SOC_MBUS_ORDER_LE, | ||
69 | }, [MBUS_IDX(SBGGR8_1X8)] = { | ||
70 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
71 | .name = "Bayer 8 BGGR", | ||
72 | .bits_per_sample = 8, | ||
73 | .packing = SOC_MBUS_PACKING_NONE, | ||
74 | .order = SOC_MBUS_ORDER_LE, | ||
75 | }, [MBUS_IDX(SBGGR10_1X10)] = { | ||
76 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
77 | .name = "Bayer 10 BGGR", | ||
78 | .bits_per_sample = 10, | ||
79 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
80 | .order = SOC_MBUS_ORDER_LE, | ||
81 | }, [MBUS_IDX(GREY8_1X8)] = { | ||
82 | .fourcc = V4L2_PIX_FMT_GREY, | ||
83 | .name = "Grey", | ||
84 | .bits_per_sample = 8, | ||
85 | .packing = SOC_MBUS_PACKING_NONE, | ||
86 | .order = SOC_MBUS_ORDER_LE, | ||
87 | }, [MBUS_IDX(Y10_1X10)] = { | ||
88 | .fourcc = V4L2_PIX_FMT_Y10, | ||
89 | .name = "Grey 10bit", | ||
90 | .bits_per_sample = 10, | ||
91 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
92 | .order = SOC_MBUS_ORDER_LE, | ||
93 | }, [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = { | ||
94 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
95 | .name = "Bayer 10 BGGR", | ||
96 | .bits_per_sample = 8, | ||
97 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
98 | .order = SOC_MBUS_ORDER_LE, | ||
99 | }, [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = { | ||
100 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
101 | .name = "Bayer 10 BGGR", | ||
102 | .bits_per_sample = 8, | ||
103 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | ||
104 | .order = SOC_MBUS_ORDER_LE, | ||
105 | }, [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = { | ||
106 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
107 | .name = "Bayer 10 BGGR", | ||
108 | .bits_per_sample = 8, | ||
109 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
110 | .order = SOC_MBUS_ORDER_BE, | ||
111 | }, [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = { | ||
112 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
113 | .name = "Bayer 10 BGGR", | ||
114 | .bits_per_sample = 8, | ||
115 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | ||
116 | .order = SOC_MBUS_ORDER_BE, | ||
117 | }, | ||
118 | }; | ||
119 | |||
120 | s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) | ||
121 | { | ||
122 | switch (mf->packing) { | ||
123 | case SOC_MBUS_PACKING_NONE: | ||
124 | return width * mf->bits_per_sample / 8; | ||
125 | case SOC_MBUS_PACKING_2X8_PADHI: | ||
126 | case SOC_MBUS_PACKING_2X8_PADLO: | ||
127 | case SOC_MBUS_PACKING_EXTEND16: | ||
128 | return width * 2; | ||
129 | } | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | EXPORT_SYMBOL(soc_mbus_bytes_per_line); | ||
133 | |||
134 | const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | ||
135 | enum v4l2_mbus_pixelcode code) | ||
136 | { | ||
137 | if ((unsigned int)(code - V4L2_MBUS_FMT_FIXED) > ARRAY_SIZE(mbus_fmt)) | ||
138 | return NULL; | ||
139 | return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1; | ||
140 | } | ||
141 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); | ||
142 | |||
143 | static int __init soc_mbus_init(void) | ||
144 | { | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static void __exit soc_mbus_exit(void) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | module_init(soc_mbus_init); | ||
153 | module_exit(soc_mbus_exit); | ||
154 | |||
155 | MODULE_DESCRIPTION("soc-camera media bus interface"); | ||
156 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
157 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 6b41865f42bd..f07a0f6b71c4 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c | |||
@@ -1307,7 +1307,6 @@ static void stk_v4l_dev_release(struct video_device *vd) | |||
1307 | 1307 | ||
1308 | static struct video_device stk_v4l_data = { | 1308 | static struct video_device stk_v4l_data = { |
1309 | .name = "stkwebcam", | 1309 | .name = "stkwebcam", |
1310 | .minor = -1, | ||
1311 | .tvnorms = V4L2_STD_UNKNOWN, | 1310 | .tvnorms = V4L2_STD_UNKNOWN, |
1312 | .current_norm = V4L2_STD_UNKNOWN, | 1311 | .current_norm = V4L2_STD_UNKNOWN, |
1313 | .fops = &v4l_stk_fops, | 1312 | .fops = &v4l_stk_fops, |
@@ -1327,8 +1326,8 @@ static int stk_register_video_device(struct stk_camera *dev) | |||
1327 | if (err) | 1326 | if (err) |
1328 | STK_ERROR("v4l registration failed\n"); | 1327 | STK_ERROR("v4l registration failed\n"); |
1329 | else | 1328 | else |
1330 | STK_INFO("Syntek USB2.0 Camera is now controlling video device" | 1329 | STK_INFO("Syntek USB2.0 Camera is now controlling device %s\n", |
1331 | " /dev/video%d\n", dev->vdev.num); | 1330 | video_device_node_name(&dev->vdev)); |
1332 | return err; | 1331 | return err; |
1333 | } | 1332 | } |
1334 | 1333 | ||
@@ -1418,8 +1417,8 @@ static void stk_camera_disconnect(struct usb_interface *interface) | |||
1418 | wake_up_interruptible(&dev->wait_frame); | 1417 | wake_up_interruptible(&dev->wait_frame); |
1419 | stk_remove_sysfs_files(&dev->vdev); | 1418 | stk_remove_sysfs_files(&dev->vdev); |
1420 | 1419 | ||
1421 | STK_INFO("Syntek USB2.0 Camera release resources " | 1420 | STK_INFO("Syntek USB2.0 Camera release resources device %s\n", |
1422 | "video device /dev/video%d\n", dev->vdev.num); | 1421 | video_device_node_name(&dev->vdev)); |
1423 | 1422 | ||
1424 | video_unregister_device(&dev->vdev); | 1423 | video_unregister_device(&dev->vdev); |
1425 | } | 1424 | } |
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index eaada39c76fd..a057824e7ebc 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c | |||
@@ -1921,7 +1921,6 @@ static const struct v4l2_file_operations saa_fops = { | |||
1921 | static struct video_device saa_template = { | 1921 | static struct video_device saa_template = { |
1922 | .name = "SAA7146A", | 1922 | .name = "SAA7146A", |
1923 | .fops = &saa_fops, | 1923 | .fops = &saa_fops, |
1924 | .minor = -1, | ||
1925 | .release = video_device_release_empty, | 1924 | .release = video_device_release_empty, |
1926 | }; | 1925 | }; |
1927 | 1926 | ||
@@ -1972,7 +1971,6 @@ static int __devinit configure_saa7146(struct pci_dev *pdev, int num) | |||
1972 | 1971 | ||
1973 | saa->id = pdev->device; | 1972 | saa->id = pdev->device; |
1974 | saa->irq = pdev->irq; | 1973 | saa->irq = pdev->irq; |
1975 | saa->video_dev.minor = -1; | ||
1976 | saa->saa7146_adr = pci_resource_start(pdev, 0); | 1974 | saa->saa7146_adr = pci_resource_start(pdev, 0); |
1977 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision); | 1975 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision); |
1978 | 1976 | ||
@@ -2134,7 +2132,7 @@ static void stradis_release_saa(struct pci_dev *pdev) | |||
2134 | free_irq(saa->irq, saa); | 2132 | free_irq(saa->irq, saa); |
2135 | if (saa->saa7146_mem) | 2133 | if (saa->saa7146_mem) |
2136 | iounmap(saa->saa7146_mem); | 2134 | iounmap(saa->saa7146_mem); |
2137 | if (saa->video_dev.minor != -1) | 2135 | if (video_is_registered(&saa->video_dev)) |
2138 | video_unregister_device(&saa->video_dev); | 2136 | video_unregister_device(&saa->video_dev); |
2139 | } | 2137 | } |
2140 | 2138 | ||
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 6a91714125d2..5938ad8702ef 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c | |||
@@ -1405,7 +1405,6 @@ static struct video_device stv680_template = { | |||
1405 | .name = "STV0680 USB camera", | 1405 | .name = "STV0680 USB camera", |
1406 | .fops = &stv680_fops, | 1406 | .fops = &stv680_fops, |
1407 | .release = video_device_release, | 1407 | .release = video_device_release, |
1408 | .minor = -1, | ||
1409 | }; | 1408 | }; |
1410 | 1409 | ||
1411 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) | 1410 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) |
@@ -1467,8 +1466,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id | |||
1467 | retval = -EIO; | 1466 | retval = -EIO; |
1468 | goto error_vdev; | 1467 | goto error_vdev; |
1469 | } | 1468 | } |
1470 | PDEBUG(0, "STV(i): registered new video device: video%d", | 1469 | PDEBUG(0, "STV(i): registered new video device: %s", |
1471 | stv680->vdev->num); | 1470 | video_device_node_name(stv680->vdev)); |
1472 | 1471 | ||
1473 | usb_set_intfdata (intf, stv680); | 1472 | usb_set_intfdata (intf, stv680); |
1474 | retval = stv680_create_sysfs_files(stv680->vdev); | 1473 | retval = stv680_create_sysfs_files(stv680->vdev); |
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 269ab044072a..5b801a6e1eea 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <media/tw9910.h> | 29 | #include <media/tw9910.h> |
30 | 30 | ||
31 | #define GET_ID(val) ((val & 0xF8) >> 3) | 31 | #define GET_ID(val) ((val & 0xF8) >> 3) |
32 | #define GET_ReV(val) (val & 0x07) | 32 | #define GET_REV(val) (val & 0x07) |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * register offset | 35 | * register offset |
@@ -117,7 +117,7 @@ | |||
117 | #define LCTL24 0x68 | 117 | #define LCTL24 0x68 |
118 | #define LCTL25 0x69 | 118 | #define LCTL25 0x69 |
119 | #define LCTL26 0x6A | 119 | #define LCTL26 0x6A |
120 | #define HSGEGIN 0x6B | 120 | #define HSBEGIN 0x6B |
121 | #define HSEND 0x6C | 121 | #define HSEND 0x6C |
122 | #define OVSDLY 0x6D | 122 | #define OVSDLY 0x6D |
123 | #define OVSEND 0x6E | 123 | #define OVSEND 0x6E |
@@ -152,7 +152,10 @@ | |||
152 | /* 1 : non-auto */ | 152 | /* 1 : non-auto */ |
153 | #define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ | 153 | #define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ |
154 | /* 0 : Vertical out ctrl by HACTIVE and DVALID */ | 154 | /* 0 : Vertical out ctrl by HACTIVE and DVALID */ |
155 | #define OEN 0x04 /* Output Enable together with TRI_SEL. */ | 155 | #define OEN_TRI_SEL_MASK 0x07 |
156 | #define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ | ||
157 | #define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ | ||
158 | #define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ | ||
156 | 159 | ||
157 | /* OUTCTR1 */ | 160 | /* OUTCTR1 */ |
158 | #define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ | 161 | #define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ |
@@ -178,11 +181,18 @@ | |||
178 | * but all register content remain unchanged. | 181 | * but all register content remain unchanged. |
179 | * This bit is self-resetting. | 182 | * This bit is self-resetting. |
180 | */ | 183 | */ |
184 | #define ACNTL1_PDN_MASK 0x0e | ||
185 | #define CLK_PDN 0x08 /* system clock power down */ | ||
186 | #define Y_PDN 0x04 /* Luma ADC power down */ | ||
187 | #define C_PDN 0x02 /* Chroma ADC power down */ | ||
188 | |||
189 | /* ACNTL2 */ | ||
190 | #define ACNTL2_PDN_MASK 0x40 | ||
191 | #define PLL_PDN 0x40 /* PLL power down */ | ||
181 | 192 | ||
182 | /* VBICNTL */ | 193 | /* VBICNTL */ |
183 | /* RTSEL : control the real time signal | 194 | |
184 | * output from the MPOUT pin | 195 | /* RTSEL : control the real time signal output from the MPOUT pin */ |
185 | */ | ||
186 | #define RTSEL_MASK 0x07 | 196 | #define RTSEL_MASK 0x07 |
187 | #define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ | 197 | #define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ |
188 | #define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ | 198 | #define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ |
@@ -226,28 +236,7 @@ struct tw9910_priv { | |||
226 | struct v4l2_subdev subdev; | 236 | struct v4l2_subdev subdev; |
227 | struct tw9910_video_info *info; | 237 | struct tw9910_video_info *info; |
228 | const struct tw9910_scale_ctrl *scale; | 238 | const struct tw9910_scale_ctrl *scale; |
229 | }; | 239 | u32 revision; |
230 | |||
231 | /* | ||
232 | * register settings | ||
233 | */ | ||
234 | |||
235 | #define ENDMARKER { 0xff, 0xff } | ||
236 | |||
237 | static const struct regval_list tw9910_default_regs[] = | ||
238 | { | ||
239 | { OPFORM, 0x00 }, | ||
240 | { OUTCTR1, VSP_LO | VSSL_VVALID | HSP_HI | HSSL_HSYNC }, | ||
241 | ENDMARKER, | ||
242 | }; | ||
243 | |||
244 | static const struct soc_camera_data_format tw9910_color_fmt[] = { | ||
245 | { | ||
246 | .name = "VYUY", | ||
247 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
248 | .depth = 16, | ||
249 | .colorspace = V4L2_COLORSPACE_SMPTE170M, | ||
250 | } | ||
251 | }; | 240 | }; |
252 | 241 | ||
253 | static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { | 242 | static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { |
@@ -340,13 +329,6 @@ static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { | |||
340 | }, | 329 | }, |
341 | }; | 330 | }; |
342 | 331 | ||
343 | static const struct tw9910_cropping_ctrl tw9910_cropping_ctrl = { | ||
344 | .vdelay = 0x0012, | ||
345 | .vactive = 0x00F0, | ||
346 | .hdelay = 0x0010, | ||
347 | .hactive = 0x02D0, | ||
348 | }; | ||
349 | |||
350 | static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { | 332 | static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { |
351 | .start = 0x0260, | 333 | .start = 0x0260, |
352 | .end = 0x0300, | 334 | .end = 0x0300, |
@@ -361,6 +343,19 @@ static struct tw9910_priv *to_tw9910(const struct i2c_client *client) | |||
361 | subdev); | 343 | subdev); |
362 | } | 344 | } |
363 | 345 | ||
346 | static int tw9910_mask_set(struct i2c_client *client, u8 command, | ||
347 | u8 mask, u8 set) | ||
348 | { | ||
349 | s32 val = i2c_smbus_read_byte_data(client, command); | ||
350 | if (val < 0) | ||
351 | return val; | ||
352 | |||
353 | val &= ~mask; | ||
354 | val |= set & mask; | ||
355 | |||
356 | return i2c_smbus_write_byte_data(client, command, val); | ||
357 | } | ||
358 | |||
364 | static int tw9910_set_scale(struct i2c_client *client, | 359 | static int tw9910_set_scale(struct i2c_client *client, |
365 | const struct tw9910_scale_ctrl *scale) | 360 | const struct tw9910_scale_ctrl *scale) |
366 | { | 361 | { |
@@ -383,47 +378,14 @@ static int tw9910_set_scale(struct i2c_client *client, | |||
383 | return ret; | 378 | return ret; |
384 | } | 379 | } |
385 | 380 | ||
386 | static int tw9910_set_cropping(struct i2c_client *client, | ||
387 | const struct tw9910_cropping_ctrl *cropping) | ||
388 | { | ||
389 | int ret; | ||
390 | |||
391 | ret = i2c_smbus_write_byte_data(client, CROP_HI, | ||
392 | (cropping->vdelay & 0x0300) >> 2 | | ||
393 | (cropping->vactive & 0x0300) >> 4 | | ||
394 | (cropping->hdelay & 0x0300) >> 6 | | ||
395 | (cropping->hactive & 0x0300) >> 8); | ||
396 | if (ret < 0) | ||
397 | return ret; | ||
398 | |||
399 | ret = i2c_smbus_write_byte_data(client, VDELAY_LO, | ||
400 | cropping->vdelay & 0x00FF); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, | ||
405 | cropping->vactive & 0x00FF); | ||
406 | if (ret < 0) | ||
407 | return ret; | ||
408 | |||
409 | ret = i2c_smbus_write_byte_data(client, HDELAY_LO, | ||
410 | cropping->hdelay & 0x00FF); | ||
411 | if (ret < 0) | ||
412 | return ret; | ||
413 | |||
414 | ret = i2c_smbus_write_byte_data(client, HACTIVE_LO, | ||
415 | cropping->hactive & 0x00FF); | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | static int tw9910_set_hsync(struct i2c_client *client, | 381 | static int tw9910_set_hsync(struct i2c_client *client, |
421 | const struct tw9910_hsync_ctrl *hsync) | 382 | const struct tw9910_hsync_ctrl *hsync) |
422 | { | 383 | { |
384 | struct tw9910_priv *priv = to_tw9910(client); | ||
423 | int ret; | 385 | int ret; |
424 | 386 | ||
425 | /* bit 10 - 3 */ | 387 | /* bit 10 - 3 */ |
426 | ret = i2c_smbus_write_byte_data(client, HSGEGIN, | 388 | ret = i2c_smbus_write_byte_data(client, HSBEGIN, |
427 | (hsync->start & 0x07F8) >> 3); | 389 | (hsync->start & 0x07F8) >> 3); |
428 | if (ret < 0) | 390 | if (ret < 0) |
429 | return ret; | 391 | return ret; |
@@ -434,50 +396,41 @@ static int tw9910_set_hsync(struct i2c_client *client, | |||
434 | if (ret < 0) | 396 | if (ret < 0) |
435 | return ret; | 397 | return ret; |
436 | 398 | ||
399 | /* So far only revisions 0 and 1 have been seen */ | ||
437 | /* bit 2 - 0 */ | 400 | /* bit 2 - 0 */ |
438 | ret = i2c_smbus_read_byte_data(client, HSLOWCTL); | 401 | if (1 == priv->revision) |
439 | if (ret < 0) | 402 | ret = tw9910_mask_set(client, HSLOWCTL, 0x77, |
440 | return ret; | 403 | (hsync->start & 0x0007) << 4 | |
441 | 404 | (hsync->end & 0x0007)); | |
442 | ret = i2c_smbus_write_byte_data(client, HSLOWCTL, | ||
443 | (ret & 0x88) | | ||
444 | (hsync->start & 0x0007) << 4 | | ||
445 | (hsync->end & 0x0007)); | ||
446 | 405 | ||
447 | return ret; | 406 | return ret; |
448 | } | 407 | } |
449 | 408 | ||
450 | static int tw9910_write_array(struct i2c_client *client, | 409 | static void tw9910_reset(struct i2c_client *client) |
451 | const struct regval_list *vals) | ||
452 | { | 410 | { |
453 | while (vals->reg_num != 0xff) { | 411 | tw9910_mask_set(client, ACNTL1, SRESET, SRESET); |
454 | int ret = i2c_smbus_write_byte_data(client, | 412 | msleep(1); |
455 | vals->reg_num, | ||
456 | vals->value); | ||
457 | if (ret < 0) | ||
458 | return ret; | ||
459 | vals++; | ||
460 | } | ||
461 | return 0; | ||
462 | } | 413 | } |
463 | 414 | ||
464 | static int tw9910_mask_set(struct i2c_client *client, u8 command, | 415 | static int tw9910_power(struct i2c_client *client, int enable) |
465 | u8 mask, u8 set) | ||
466 | { | 416 | { |
467 | s32 val = i2c_smbus_read_byte_data(client, command); | 417 | int ret; |
468 | if (val < 0) | 418 | u8 acntl1; |
469 | return val; | 419 | u8 acntl2; |
470 | 420 | ||
471 | val &= ~mask; | 421 | if (enable) { |
472 | val |= set & mask; | 422 | acntl1 = 0; |
423 | acntl2 = 0; | ||
424 | } else { | ||
425 | acntl1 = CLK_PDN | Y_PDN | C_PDN; | ||
426 | acntl2 = PLL_PDN; | ||
427 | } | ||
473 | 428 | ||
474 | return i2c_smbus_write_byte_data(client, command, val); | 429 | ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); |
475 | } | 430 | if (ret < 0) |
431 | return ret; | ||
476 | 432 | ||
477 | static void tw9910_reset(struct i2c_client *client) | 433 | return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); |
478 | { | ||
479 | i2c_smbus_write_byte_data(client, ACNTL1, SRESET); | ||
480 | msleep(1); | ||
481 | } | 434 | } |
482 | 435 | ||
483 | static const struct tw9910_scale_ctrl* | 436 | static const struct tw9910_scale_ctrl* |
@@ -518,27 +471,62 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) | |||
518 | { | 471 | { |
519 | struct i2c_client *client = sd->priv; | 472 | struct i2c_client *client = sd->priv; |
520 | struct tw9910_priv *priv = to_tw9910(client); | 473 | struct tw9910_priv *priv = to_tw9910(client); |
474 | u8 val; | ||
475 | int ret; | ||
521 | 476 | ||
522 | if (!enable) | 477 | if (!enable) { |
523 | return 0; | 478 | switch (priv->revision) { |
479 | case 0: | ||
480 | val = OEN_TRI_SEL_ALL_OFF_r0; | ||
481 | break; | ||
482 | case 1: | ||
483 | val = OEN_TRI_SEL_ALL_OFF_r1; | ||
484 | break; | ||
485 | default: | ||
486 | dev_err(&client->dev, "un-supported revision\n"); | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | } else { | ||
490 | val = OEN_TRI_SEL_ALL_ON; | ||
524 | 491 | ||
525 | if (!priv->scale) { | 492 | if (!priv->scale) { |
526 | dev_err(&client->dev, "norm select error\n"); | 493 | dev_err(&client->dev, "norm select error\n"); |
527 | return -EPERM; | 494 | return -EPERM; |
495 | } | ||
496 | |||
497 | dev_dbg(&client->dev, "%s %dx%d\n", | ||
498 | priv->scale->name, | ||
499 | priv->scale->width, | ||
500 | priv->scale->height); | ||
528 | } | 501 | } |
529 | 502 | ||
530 | dev_dbg(&client->dev, "%s %dx%d\n", | 503 | ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); |
531 | priv->scale->name, | 504 | if (ret < 0) |
532 | priv->scale->width, | 505 | return ret; |
533 | priv->scale->height); | ||
534 | 506 | ||
535 | return 0; | 507 | return tw9910_power(client, enable); |
536 | } | 508 | } |
537 | 509 | ||
538 | static int tw9910_set_bus_param(struct soc_camera_device *icd, | 510 | static int tw9910_set_bus_param(struct soc_camera_device *icd, |
539 | unsigned long flags) | 511 | unsigned long flags) |
540 | { | 512 | { |
541 | return 0; | 513 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
514 | struct i2c_client *client = sd->priv; | ||
515 | u8 val = VSSL_VVALID | HSSL_DVALID; | ||
516 | |||
517 | /* | ||
518 | * set OUTCTR1 | ||
519 | * | ||
520 | * We use VVALID and DVALID signals to control VSYNC and HSYNC | ||
521 | * outputs, in this mode their polarity is inverted. | ||
522 | */ | ||
523 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | ||
524 | val |= HSP_HI; | ||
525 | |||
526 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | ||
527 | val |= VSP_HI; | ||
528 | |||
529 | return i2c_smbus_write_byte_data(client, OUTCTR1, val); | ||
542 | } | 530 | } |
543 | 531 | ||
544 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | 532 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) |
@@ -548,6 +536,7 @@ static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | |||
548 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 536 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
549 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | 537 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | |
550 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | 538 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | |
539 | SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | | ||
551 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | 540 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; |
552 | 541 | ||
553 | return soc_camera_apply_sensor_flags(icl, flags); | 542 | return soc_camera_apply_sensor_flags(icl, flags); |
@@ -576,8 +565,11 @@ static int tw9910_enum_input(struct soc_camera_device *icd, | |||
576 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, | 565 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, |
577 | struct v4l2_dbg_chip_ident *id) | 566 | struct v4l2_dbg_chip_ident *id) |
578 | { | 567 | { |
568 | struct i2c_client *client = sd->priv; | ||
569 | struct tw9910_priv *priv = to_tw9910(client); | ||
570 | |||
579 | id->ident = V4L2_IDENT_TW9910; | 571 | id->ident = V4L2_IDENT_TW9910; |
580 | id->revision = 0; | 572 | id->revision = priv->revision; |
581 | 573 | ||
582 | return 0; | 574 | return 0; |
583 | } | 575 | } |
@@ -596,7 +588,8 @@ static int tw9910_g_register(struct v4l2_subdev *sd, | |||
596 | if (ret < 0) | 588 | if (ret < 0) |
597 | return ret; | 589 | return ret; |
598 | 590 | ||
599 | /* ret = int | 591 | /* |
592 | * ret = int | ||
600 | * reg->val = __u64 | 593 | * reg->val = __u64 |
601 | */ | 594 | */ |
602 | reg->val = (__u64)ret; | 595 | reg->val = (__u64)ret; |
@@ -637,9 +630,6 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
637 | * reset hardware | 630 | * reset hardware |
638 | */ | 631 | */ |
639 | tw9910_reset(client); | 632 | tw9910_reset(client); |
640 | ret = tw9910_write_array(client, tw9910_default_regs); | ||
641 | if (ret < 0) | ||
642 | goto tw9910_set_fmt_error; | ||
643 | 633 | ||
644 | /* | 634 | /* |
645 | * set bus width | 635 | * set bus width |
@@ -688,13 +678,6 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
688 | goto tw9910_set_fmt_error; | 678 | goto tw9910_set_fmt_error; |
689 | 679 | ||
690 | /* | 680 | /* |
691 | * set cropping | ||
692 | */ | ||
693 | ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl); | ||
694 | if (ret < 0) | ||
695 | goto tw9910_set_fmt_error; | ||
696 | |||
697 | /* | ||
698 | * set hsync | 681 | * set hsync |
699 | */ | 682 | */ |
700 | ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); | 683 | ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); |
@@ -762,11 +745,11 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
762 | return 0; | 745 | return 0; |
763 | } | 746 | } |
764 | 747 | ||
765 | static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 748 | static int tw9910_g_fmt(struct v4l2_subdev *sd, |
749 | struct v4l2_mbus_framefmt *mf) | ||
766 | { | 750 | { |
767 | struct i2c_client *client = sd->priv; | 751 | struct i2c_client *client = sd->priv; |
768 | struct tw9910_priv *priv = to_tw9910(client); | 752 | struct tw9910_priv *priv = to_tw9910(client); |
769 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
770 | 753 | ||
771 | if (!priv->scale) { | 754 | if (!priv->scale) { |
772 | int ret; | 755 | int ret; |
@@ -783,74 +766,76 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
783 | return ret; | 766 | return ret; |
784 | } | 767 | } |
785 | 768 | ||
786 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 769 | mf->width = priv->scale->width; |
787 | 770 | mf->height = priv->scale->height; | |
788 | pix->width = priv->scale->width; | 771 | mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; |
789 | pix->height = priv->scale->height; | 772 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
790 | pix->pixelformat = V4L2_PIX_FMT_VYUY; | 773 | mf->field = V4L2_FIELD_INTERLACED_BT; |
791 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
792 | pix->field = V4L2_FIELD_INTERLACED; | ||
793 | 774 | ||
794 | return 0; | 775 | return 0; |
795 | } | 776 | } |
796 | 777 | ||
797 | static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 778 | static int tw9910_s_fmt(struct v4l2_subdev *sd, |
779 | struct v4l2_mbus_framefmt *mf) | ||
798 | { | 780 | { |
799 | struct i2c_client *client = sd->priv; | 781 | struct i2c_client *client = sd->priv; |
800 | struct tw9910_priv *priv = to_tw9910(client); | 782 | struct tw9910_priv *priv = to_tw9910(client); |
801 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
802 | /* See tw9910_s_crop() - no proper cropping support */ | 783 | /* See tw9910_s_crop() - no proper cropping support */ |
803 | struct v4l2_crop a = { | 784 | struct v4l2_crop a = { |
804 | .c = { | 785 | .c = { |
805 | .left = 0, | 786 | .left = 0, |
806 | .top = 0, | 787 | .top = 0, |
807 | .width = pix->width, | 788 | .width = mf->width, |
808 | .height = pix->height, | 789 | .height = mf->height, |
809 | }, | 790 | }, |
810 | }; | 791 | }; |
811 | int i, ret; | 792 | int ret; |
793 | |||
794 | WARN_ON(mf->field != V4L2_FIELD_ANY && | ||
795 | mf->field != V4L2_FIELD_INTERLACED_BT); | ||
812 | 796 | ||
813 | /* | 797 | /* |
814 | * check color format | 798 | * check color format |
815 | */ | 799 | */ |
816 | for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++) | 800 | if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE) |
817 | if (pix->pixelformat == tw9910_color_fmt[i].fourcc) | ||
818 | break; | ||
819 | |||
820 | if (i == ARRAY_SIZE(tw9910_color_fmt)) | ||
821 | return -EINVAL; | 801 | return -EINVAL; |
822 | 802 | ||
803 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
804 | |||
823 | ret = tw9910_s_crop(sd, &a); | 805 | ret = tw9910_s_crop(sd, &a); |
824 | if (!ret) { | 806 | if (!ret) { |
825 | pix->width = priv->scale->width; | 807 | mf->width = priv->scale->width; |
826 | pix->height = priv->scale->height; | 808 | mf->height = priv->scale->height; |
827 | } | 809 | } |
828 | return ret; | 810 | return ret; |
829 | } | 811 | } |
830 | 812 | ||
831 | static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 813 | static int tw9910_try_fmt(struct v4l2_subdev *sd, |
814 | struct v4l2_mbus_framefmt *mf) | ||
832 | { | 815 | { |
833 | struct i2c_client *client = sd->priv; | 816 | struct i2c_client *client = sd->priv; |
834 | struct soc_camera_device *icd = client->dev.platform_data; | 817 | struct soc_camera_device *icd = client->dev.platform_data; |
835 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
836 | const struct tw9910_scale_ctrl *scale; | 818 | const struct tw9910_scale_ctrl *scale; |
837 | 819 | ||
838 | if (V4L2_FIELD_ANY == pix->field) { | 820 | if (V4L2_FIELD_ANY == mf->field) { |
839 | pix->field = V4L2_FIELD_INTERLACED; | 821 | mf->field = V4L2_FIELD_INTERLACED_BT; |
840 | } else if (V4L2_FIELD_INTERLACED != pix->field) { | 822 | } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { |
841 | dev_err(&client->dev, "Field type invalid.\n"); | 823 | dev_err(&client->dev, "Field type %d invalid.\n", mf->field); |
842 | return -EINVAL; | 824 | return -EINVAL; |
843 | } | 825 | } |
844 | 826 | ||
827 | mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; | ||
828 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
829 | |||
845 | /* | 830 | /* |
846 | * select suitable norm | 831 | * select suitable norm |
847 | */ | 832 | */ |
848 | scale = tw9910_select_norm(icd, pix->width, pix->height); | 833 | scale = tw9910_select_norm(icd, mf->width, mf->height); |
849 | if (!scale) | 834 | if (!scale) |
850 | return -EINVAL; | 835 | return -EINVAL; |
851 | 836 | ||
852 | pix->width = scale->width; | 837 | mf->width = scale->width; |
853 | pix->height = scale->height; | 838 | mf->height = scale->height; |
854 | 839 | ||
855 | return 0; | 840 | return 0; |
856 | } | 841 | } |
@@ -859,7 +844,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, | |||
859 | struct i2c_client *client) | 844 | struct i2c_client *client) |
860 | { | 845 | { |
861 | struct tw9910_priv *priv = to_tw9910(client); | 846 | struct tw9910_priv *priv = to_tw9910(client); |
862 | s32 val; | 847 | s32 id; |
863 | 848 | ||
864 | /* | 849 | /* |
865 | * We must have a parent by now. And it cannot be a wrong one. | 850 | * We must have a parent by now. And it cannot be a wrong one. |
@@ -878,23 +863,24 @@ static int tw9910_video_probe(struct soc_camera_device *icd, | |||
878 | return -ENODEV; | 863 | return -ENODEV; |
879 | } | 864 | } |
880 | 865 | ||
881 | icd->formats = tw9910_color_fmt; | ||
882 | icd->num_formats = ARRAY_SIZE(tw9910_color_fmt); | ||
883 | |||
884 | /* | 866 | /* |
885 | * check and show Product ID | 867 | * check and show Product ID |
868 | * So far only revisions 0 and 1 have been seen | ||
886 | */ | 869 | */ |
887 | val = i2c_smbus_read_byte_data(client, ID); | 870 | id = i2c_smbus_read_byte_data(client, ID); |
871 | priv->revision = GET_REV(id); | ||
872 | id = GET_ID(id); | ||
888 | 873 | ||
889 | if (0x0B != GET_ID(val) || | 874 | if (0x0B != id || |
890 | 0x00 != GET_ReV(val)) { | 875 | 0x01 < priv->revision) { |
891 | dev_err(&client->dev, | 876 | dev_err(&client->dev, |
892 | "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val)); | 877 | "Product ID error %x:%x\n", |
878 | id, priv->revision); | ||
893 | return -ENODEV; | 879 | return -ENODEV; |
894 | } | 880 | } |
895 | 881 | ||
896 | dev_info(&client->dev, | 882 | dev_info(&client->dev, |
897 | "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val)); | 883 | "tw9910 Product ID %0x:%0x\n", id, priv->revision); |
898 | 884 | ||
899 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; | 885 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; |
900 | icd->vdev->current_norm = V4L2_STD_NTSC; | 886 | icd->vdev->current_norm = V4L2_STD_NTSC; |
@@ -917,14 +903,25 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | |||
917 | #endif | 903 | #endif |
918 | }; | 904 | }; |
919 | 905 | ||
906 | static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index, | ||
907 | enum v4l2_mbus_pixelcode *code) | ||
908 | { | ||
909 | if (index) | ||
910 | return -EINVAL; | ||
911 | |||
912 | *code = V4L2_MBUS_FMT_YUYV8_2X8_BE; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
920 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | 916 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { |
921 | .s_stream = tw9910_s_stream, | 917 | .s_stream = tw9910_s_stream, |
922 | .g_fmt = tw9910_g_fmt, | 918 | .g_mbus_fmt = tw9910_g_fmt, |
923 | .s_fmt = tw9910_s_fmt, | 919 | .s_mbus_fmt = tw9910_s_fmt, |
924 | .try_fmt = tw9910_try_fmt, | 920 | .try_mbus_fmt = tw9910_try_fmt, |
925 | .cropcap = tw9910_cropcap, | 921 | .cropcap = tw9910_cropcap, |
926 | .g_crop = tw9910_g_crop, | 922 | .g_crop = tw9910_g_crop, |
927 | .s_crop = tw9910_s_crop, | 923 | .s_crop = tw9910_s_crop, |
924 | .enum_mbus_fmt = tw9910_enum_fmt, | ||
928 | }; | 925 | }; |
929 | 926 | ||
930 | static struct v4l2_subdev_ops tw9910_subdev_ops = { | 927 | static struct v4l2_subdev_ops tw9910_subdev_ops = { |
@@ -954,10 +951,10 @@ static int tw9910_probe(struct i2c_client *client, | |||
954 | } | 951 | } |
955 | 952 | ||
956 | icl = to_soc_camera_link(icd); | 953 | icl = to_soc_camera_link(icd); |
957 | if (!icl) | 954 | if (!icl || !icl->priv) |
958 | return -EINVAL; | 955 | return -EINVAL; |
959 | 956 | ||
960 | info = container_of(icl, struct tw9910_video_info, link); | 957 | info = icl->priv; |
961 | 958 | ||
962 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 959 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
963 | dev_err(&client->dev, | 960 | dev_err(&client->dev, |
@@ -975,7 +972,7 @@ static int tw9910_probe(struct i2c_client *client, | |||
975 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); | 972 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); |
976 | 973 | ||
977 | icd->ops = &tw9910_ops; | 974 | icd->ops = &tw9910_ops; |
978 | icd->iface = info->link.bus_id; | 975 | icd->iface = icl->bus_id; |
979 | 976 | ||
980 | ret = tw9910_video_probe(icd, client); | 977 | ret = tw9910_video_probe(icd, client); |
981 | if (ret) { | 978 | if (ret) { |
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index dea8b321fb4a..5ac37c6c4313 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c | |||
@@ -1053,9 +1053,9 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) | |||
1053 | "%s: video_register_device() successful\n", __func__); | 1053 | "%s: video_register_device() successful\n", __func__); |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n", | 1056 | dev_info(&uvd->dev->dev, "%s on %s: canvas=%s videosize=%s\n", |
1057 | (uvd->handle != NULL) ? uvd->handle->drvName : "???", | 1057 | (uvd->handle != NULL) ? uvd->handle->drvName : "???", |
1058 | uvd->vdev.num, tmp2, tmp1); | 1058 | video_device_node_name(&uvd->vdev), tmp2, tmp1); |
1059 | 1059 | ||
1060 | usb_get_dev(uvd->dev); | 1060 | usb_get_dev(uvd->dev); |
1061 | return 0; | 1061 | return 0; |
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 45fce39ec9ad..6030410c6677 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c | |||
@@ -796,7 +796,6 @@ static const struct v4l2_file_operations vicam_fops = { | |||
796 | static struct video_device vicam_template = { | 796 | static struct video_device vicam_template = { |
797 | .name = "ViCam-based USB Camera", | 797 | .name = "ViCam-based USB Camera", |
798 | .fops = &vicam_fops, | 798 | .fops = &vicam_fops, |
799 | .minor = -1, | ||
800 | .release = video_device_release_empty, | 799 | .release = video_device_release_empty, |
801 | }; | 800 | }; |
802 | 801 | ||
@@ -873,8 +872,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) | |||
873 | return -EIO; | 872 | return -EIO; |
874 | } | 873 | } |
875 | 874 | ||
876 | printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n", | 875 | printk(KERN_INFO "ViCam webcam driver now controlling device %s\n", |
877 | cam->vdev.num); | 876 | video_device_node_name(&cam->vdev)); |
878 | 877 | ||
879 | usb_set_intfdata (intf, cam); | 878 | usb_set_intfdata (intf, cam); |
880 | 879 | ||
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index c19f51dba2ee..0613922997e0 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c | |||
@@ -215,8 +215,8 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) | |||
215 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, | 215 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, |
216 | sizeof(struct i2c_adapter)); | 216 | sizeof(struct i2c_adapter)); |
217 | 217 | ||
218 | sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), | 218 | sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name, |
219 | " #%d", usbvision->vdev->num); | 219 | usbvision->dev->bus->busnum, usbvision->dev->devpath); |
220 | PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); | 220 | PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); |
221 | usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; | 221 | usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; |
222 | 222 | ||
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index c07b0ac452ab..1054546db908 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c | |||
@@ -1328,7 +1328,6 @@ static struct video_device usbvision_video_template = { | |||
1328 | .ioctl_ops = &usbvision_ioctl_ops, | 1328 | .ioctl_ops = &usbvision_ioctl_ops, |
1329 | .name = "usbvision-video", | 1329 | .name = "usbvision-video", |
1330 | .release = video_device_release, | 1330 | .release = video_device_release, |
1331 | .minor = -1, | ||
1332 | .tvnorms = USBVISION_NORMS, | 1331 | .tvnorms = USBVISION_NORMS, |
1333 | .current_norm = V4L2_STD_PAL | 1332 | .current_norm = V4L2_STD_PAL |
1334 | }; | 1333 | }; |
@@ -1362,7 +1361,6 @@ static struct video_device usbvision_radio_template = { | |||
1362 | .fops = &usbvision_radio_fops, | 1361 | .fops = &usbvision_radio_fops, |
1363 | .name = "usbvision-radio", | 1362 | .name = "usbvision-radio", |
1364 | .release = video_device_release, | 1363 | .release = video_device_release, |
1365 | .minor = -1, | ||
1366 | .ioctl_ops = &usbvision_radio_ioctl_ops, | 1364 | .ioctl_ops = &usbvision_radio_ioctl_ops, |
1367 | 1365 | ||
1368 | .tvnorms = USBVISION_NORMS, | 1366 | .tvnorms = USBVISION_NORMS, |
@@ -1382,7 +1380,6 @@ static struct video_device usbvision_vbi_template= | |||
1382 | .fops = &usbvision_vbi_fops, | 1380 | .fops = &usbvision_vbi_fops, |
1383 | .release = video_device_release, | 1381 | .release = video_device_release, |
1384 | .name = "usbvision-vbi", | 1382 | .name = "usbvision-vbi", |
1385 | .minor = -1, | ||
1386 | }; | 1383 | }; |
1387 | 1384 | ||
1388 | 1385 | ||
@@ -1404,7 +1401,6 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, | |||
1404 | return NULL; | 1401 | return NULL; |
1405 | } | 1402 | } |
1406 | *vdev = *vdev_template; | 1403 | *vdev = *vdev_template; |
1407 | // vdev->minor = -1; | ||
1408 | vdev->v4l2_dev = &usbvision->v4l2_dev; | 1404 | vdev->v4l2_dev = &usbvision->v4l2_dev; |
1409 | snprintf(vdev->name, sizeof(vdev->name), "%s", name); | 1405 | snprintf(vdev->name, sizeof(vdev->name), "%s", name); |
1410 | video_set_drvdata(vdev, usbvision); | 1406 | video_set_drvdata(vdev, usbvision); |
@@ -1416,9 +1412,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) | |||
1416 | { | 1412 | { |
1417 | // vbi Device: | 1413 | // vbi Device: |
1418 | if (usbvision->vbi) { | 1414 | if (usbvision->vbi) { |
1419 | PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", | 1415 | PDEBUG(DBG_PROBE, "unregister %s [v4l2]", |
1420 | usbvision->vbi->num); | 1416 | video_device_node_name(usbvision->vbi)); |
1421 | if (usbvision->vbi->minor != -1) { | 1417 | if (video_is_registered(usbvision->vbi)) { |
1422 | video_unregister_device(usbvision->vbi); | 1418 | video_unregister_device(usbvision->vbi); |
1423 | } else { | 1419 | } else { |
1424 | video_device_release(usbvision->vbi); | 1420 | video_device_release(usbvision->vbi); |
@@ -1428,9 +1424,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) | |||
1428 | 1424 | ||
1429 | // Radio Device: | 1425 | // Radio Device: |
1430 | if (usbvision->rdev) { | 1426 | if (usbvision->rdev) { |
1431 | PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", | 1427 | PDEBUG(DBG_PROBE, "unregister %s [v4l2]", |
1432 | usbvision->rdev->num); | 1428 | video_device_node_name(usbvision->rdev)); |
1433 | if (usbvision->rdev->minor != -1) { | 1429 | if (video_is_registered(usbvision->rdev)) { |
1434 | video_unregister_device(usbvision->rdev); | 1430 | video_unregister_device(usbvision->rdev); |
1435 | } else { | 1431 | } else { |
1436 | video_device_release(usbvision->rdev); | 1432 | video_device_release(usbvision->rdev); |
@@ -1440,9 +1436,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) | |||
1440 | 1436 | ||
1441 | // Video Device: | 1437 | // Video Device: |
1442 | if (usbvision->vdev) { | 1438 | if (usbvision->vdev) { |
1443 | PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", | 1439 | PDEBUG(DBG_PROBE, "unregister %s [v4l2]", |
1444 | usbvision->vdev->num); | 1440 | video_device_node_name(usbvision->vdev)); |
1445 | if (usbvision->vdev->minor != -1) { | 1441 | if (video_is_registered(usbvision->vdev)) { |
1446 | video_unregister_device(usbvision->vdev); | 1442 | video_unregister_device(usbvision->vdev); |
1447 | } else { | 1443 | } else { |
1448 | video_device_release(usbvision->vdev); | 1444 | video_device_release(usbvision->vdev); |
@@ -1466,8 +1462,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) | |||
1466 | video_nr)<0) { | 1462 | video_nr)<0) { |
1467 | goto err_exit; | 1463 | goto err_exit; |
1468 | } | 1464 | } |
1469 | printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", | 1465 | printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", |
1470 | usbvision->nr, usbvision->vdev->num); | 1466 | usbvision->nr, video_device_node_name(usbvision->vdev)); |
1471 | 1467 | ||
1472 | // Radio Device: | 1468 | // Radio Device: |
1473 | if (usbvision_device_data[usbvision->DevModel].Radio) { | 1469 | if (usbvision_device_data[usbvision->DevModel].Radio) { |
@@ -1483,8 +1479,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) | |||
1483 | radio_nr)<0) { | 1479 | radio_nr)<0) { |
1484 | goto err_exit; | 1480 | goto err_exit; |
1485 | } | 1481 | } |
1486 | printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", | 1482 | printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", |
1487 | usbvision->nr, usbvision->rdev->num); | 1483 | usbvision->nr, video_device_node_name(usbvision->rdev)); |
1488 | } | 1484 | } |
1489 | // vbi Device: | 1485 | // vbi Device: |
1490 | if (usbvision_device_data[usbvision->DevModel].vbi) { | 1486 | if (usbvision_device_data[usbvision->DevModel].vbi) { |
@@ -1499,8 +1495,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) | |||
1499 | vbi_nr)<0) { | 1495 | vbi_nr)<0) { |
1500 | goto err_exit; | 1496 | goto err_exit; |
1501 | } | 1497 | } |
1502 | printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", | 1498 | printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device %s [v4l2] (Not Working Yet!)\n", |
1503 | usbvision->nr, usbvision->vbi->num); | 1499 | usbvision->nr, video_device_node_name(usbvision->vbi)); |
1504 | } | 1500 | } |
1505 | // all done | 1501 | // all done |
1506 | return 0; | 1502 | return 0; |
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index c31bc50113bc..391cccca7ffc 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -1651,7 +1651,6 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1651 | * get another one. | 1651 | * get another one. |
1652 | */ | 1652 | */ |
1653 | vdev->parent = &dev->intf->dev; | 1653 | vdev->parent = &dev->intf->dev; |
1654 | vdev->minor = -1; | ||
1655 | vdev->fops = &uvc_fops; | 1654 | vdev->fops = &uvc_fops; |
1656 | vdev->release = uvc_release; | 1655 | vdev->release = uvc_release; |
1657 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | 1656 | strlcpy(vdev->name, dev->name, sizeof vdev->name); |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 05139a4f14f6..9a9802830d41 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -145,7 +145,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, | |||
145 | uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " | 145 | uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " |
146 | "compliance - GET_MIN/MAX(PROBE) incorrectly " | 146 | "compliance - GET_MIN/MAX(PROBE) incorrectly " |
147 | "supported. Enabling workaround.\n"); | 147 | "supported. Enabling workaround.\n"); |
148 | memset(ctrl, 0, sizeof ctrl); | 148 | memset(ctrl, 0, sizeof *ctrl); |
149 | ctrl->wCompQuality = le16_to_cpup((__le16 *)data); | 149 | ctrl->wCompQuality = le16_to_cpup((__le16 *)data); |
150 | ret = 0; | 150 | ret = 0; |
151 | goto out; | 151 | goto out; |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index e8e5affbabce..36b5cb86fb57 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -1024,3 +1024,50 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, | |||
1024 | } | 1024 | } |
1025 | } | 1025 | } |
1026 | EXPORT_SYMBOL_GPL(v4l_bound_align_image); | 1026 | EXPORT_SYMBOL_GPL(v4l_bound_align_image); |
1027 | |||
1028 | /** | ||
1029 | * v4l_fill_dv_preset_info - fill description of a digital video preset | ||
1030 | * @preset - preset value | ||
1031 | * @info - pointer to struct v4l2_dv_enum_preset | ||
1032 | * | ||
1033 | * drivers can use this helper function to fill description of dv preset | ||
1034 | * in info. | ||
1035 | */ | ||
1036 | int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) | ||
1037 | { | ||
1038 | static const struct v4l2_dv_preset_info { | ||
1039 | u16 width; | ||
1040 | u16 height; | ||
1041 | const char *name; | ||
1042 | } dv_presets[] = { | ||
1043 | { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ | ||
1044 | { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ | ||
1045 | { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ | ||
1046 | { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ | ||
1047 | { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ | ||
1048 | { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ | ||
1049 | { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ | ||
1050 | { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ | ||
1051 | { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ | ||
1052 | { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ | ||
1053 | { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ | ||
1054 | { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ | ||
1055 | { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ | ||
1056 | { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ | ||
1057 | { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ | ||
1058 | { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ | ||
1059 | { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ | ||
1060 | { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ | ||
1061 | { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ | ||
1062 | }; | ||
1063 | |||
1064 | if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) | ||
1065 | return -EINVAL; | ||
1066 | |||
1067 | info->preset = preset; | ||
1068 | info->width = dv_presets[preset].width; | ||
1069 | info->height = dv_presets[preset].height; | ||
1070 | strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); | ||
1071 | return 0; | ||
1072 | } | ||
1073 | EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); | ||
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 997975d5e024..c4150bd26337 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
@@ -1077,6 +1077,12 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
1077 | case VIDIOC_DBG_G_REGISTER: | 1077 | case VIDIOC_DBG_G_REGISTER: |
1078 | case VIDIOC_DBG_G_CHIP_IDENT: | 1078 | case VIDIOC_DBG_G_CHIP_IDENT: |
1079 | case VIDIOC_S_HW_FREQ_SEEK: | 1079 | case VIDIOC_S_HW_FREQ_SEEK: |
1080 | case VIDIOC_ENUM_DV_PRESETS: | ||
1081 | case VIDIOC_S_DV_PRESET: | ||
1082 | case VIDIOC_G_DV_PRESET: | ||
1083 | case VIDIOC_QUERY_DV_PRESET: | ||
1084 | case VIDIOC_S_DV_TIMINGS: | ||
1085 | case VIDIOC_G_DV_TIMINGS: | ||
1080 | ret = do_video_ioctl(file, cmd, arg); | 1086 | ret = do_video_ioctl(file, cmd, arg); |
1081 | break; | 1087 | break; |
1082 | 1088 | ||
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 500cbe9891ac..709069916068 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -189,7 +189,7 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, | |||
189 | 189 | ||
190 | if (!vdev->fops->read) | 190 | if (!vdev->fops->read) |
191 | return -EINVAL; | 191 | return -EINVAL; |
192 | if (video_is_unregistered(vdev)) | 192 | if (!video_is_registered(vdev)) |
193 | return -EIO; | 193 | return -EIO; |
194 | return vdev->fops->read(filp, buf, sz, off); | 194 | return vdev->fops->read(filp, buf, sz, off); |
195 | } | 195 | } |
@@ -201,7 +201,7 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, | |||
201 | 201 | ||
202 | if (!vdev->fops->write) | 202 | if (!vdev->fops->write) |
203 | return -EINVAL; | 203 | return -EINVAL; |
204 | if (video_is_unregistered(vdev)) | 204 | if (!video_is_registered(vdev)) |
205 | return -EIO; | 205 | return -EIO; |
206 | return vdev->fops->write(filp, buf, sz, off); | 206 | return vdev->fops->write(filp, buf, sz, off); |
207 | } | 207 | } |
@@ -210,7 +210,7 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) | |||
210 | { | 210 | { |
211 | struct video_device *vdev = video_devdata(filp); | 211 | struct video_device *vdev = video_devdata(filp); |
212 | 212 | ||
213 | if (!vdev->fops->poll || video_is_unregistered(vdev)) | 213 | if (!vdev->fops->poll || !video_is_registered(vdev)) |
214 | return DEFAULT_POLLMASK; | 214 | return DEFAULT_POLLMASK; |
215 | return vdev->fops->poll(filp, poll); | 215 | return vdev->fops->poll(filp, poll); |
216 | } | 216 | } |
@@ -250,7 +250,7 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp, | |||
250 | 250 | ||
251 | if (!vdev->fops->get_unmapped_area) | 251 | if (!vdev->fops->get_unmapped_area) |
252 | return -ENOSYS; | 252 | return -ENOSYS; |
253 | if (video_is_unregistered(vdev)) | 253 | if (!video_is_registered(vdev)) |
254 | return -ENODEV; | 254 | return -ENODEV; |
255 | return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); | 255 | return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); |
256 | } | 256 | } |
@@ -260,8 +260,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) | |||
260 | { | 260 | { |
261 | struct video_device *vdev = video_devdata(filp); | 261 | struct video_device *vdev = video_devdata(filp); |
262 | 262 | ||
263 | if (!vdev->fops->mmap || | 263 | if (!vdev->fops->mmap || !video_is_registered(vdev)) |
264 | video_is_unregistered(vdev)) | ||
265 | return -ENODEV; | 264 | return -ENODEV; |
266 | return vdev->fops->mmap(filp, vm); | 265 | return vdev->fops->mmap(filp, vm); |
267 | } | 266 | } |
@@ -277,7 +276,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) | |||
277 | vdev = video_devdata(filp); | 276 | vdev = video_devdata(filp); |
278 | /* return ENODEV if the video device has been removed | 277 | /* return ENODEV if the video device has been removed |
279 | already or if it is not registered anymore. */ | 278 | already or if it is not registered anymore. */ |
280 | if (vdev == NULL || video_is_unregistered(vdev)) { | 279 | if (vdev == NULL || !video_is_registered(vdev)) { |
281 | mutex_unlock(&videodev_lock); | 280 | mutex_unlock(&videodev_lock); |
282 | return -ENODEV; | 281 | return -ENODEV; |
283 | } | 282 | } |
@@ -551,10 +550,11 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
551 | vdev->dev.release = v4l2_device_release; | 550 | vdev->dev.release = v4l2_device_release; |
552 | 551 | ||
553 | if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) | 552 | if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) |
554 | printk(KERN_WARNING "%s: requested %s%d, got %s%d\n", | 553 | printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, |
555 | __func__, name_base, nr, name_base, vdev->num); | 554 | name_base, nr, video_device_node_name(vdev)); |
556 | 555 | ||
557 | /* Part 5: Activate this minor. The char device can now be used. */ | 556 | /* Part 5: Activate this minor. The char device can now be used. */ |
557 | set_bit(V4L2_FL_REGISTERED, &vdev->flags); | ||
558 | mutex_lock(&videodev_lock); | 558 | mutex_lock(&videodev_lock); |
559 | video_device[vdev->minor] = vdev; | 559 | video_device[vdev->minor] = vdev; |
560 | mutex_unlock(&videodev_lock); | 560 | mutex_unlock(&videodev_lock); |
@@ -593,11 +593,11 @@ EXPORT_SYMBOL(video_register_device_no_warn); | |||
593 | void video_unregister_device(struct video_device *vdev) | 593 | void video_unregister_device(struct video_device *vdev) |
594 | { | 594 | { |
595 | /* Check if vdev was ever registered at all */ | 595 | /* Check if vdev was ever registered at all */ |
596 | if (!vdev || vdev->minor < 0) | 596 | if (!vdev || !video_is_registered(vdev)) |
597 | return; | 597 | return; |
598 | 598 | ||
599 | mutex_lock(&videodev_lock); | 599 | mutex_lock(&videodev_lock); |
600 | set_bit(V4L2_FL_UNREGISTERED, &vdev->flags); | 600 | clear_bit(V4L2_FL_REGISTERED, &vdev->flags); |
601 | mutex_unlock(&videodev_lock); | 601 | mutex_unlock(&videodev_lock); |
602 | device_unregister(&vdev->dev); | 602 | device_unregister(&vdev->dev); |
603 | } | 603 | } |
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 30cc3347ae52..4b11257c3184 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -284,6 +284,12 @@ static const char *v4l2_ioctls[] = { | |||
284 | [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", | 284 | [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", |
285 | [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", | 285 | [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", |
286 | #endif | 286 | #endif |
287 | [_IOC_NR(VIDIOC_ENUM_DV_PRESETS)] = "VIDIOC_ENUM_DV_PRESETS", | ||
288 | [_IOC_NR(VIDIOC_S_DV_PRESET)] = "VIDIOC_S_DV_PRESET", | ||
289 | [_IOC_NR(VIDIOC_G_DV_PRESET)] = "VIDIOC_G_DV_PRESET", | ||
290 | [_IOC_NR(VIDIOC_QUERY_DV_PRESET)] = "VIDIOC_QUERY_DV_PRESET", | ||
291 | [_IOC_NR(VIDIOC_S_DV_TIMINGS)] = "VIDIOC_S_DV_TIMINGS", | ||
292 | [_IOC_NR(VIDIOC_G_DV_TIMINGS)] = "VIDIOC_G_DV_TIMINGS", | ||
287 | }; | 293 | }; |
288 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 294 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
289 | 295 | ||
@@ -1135,6 +1141,19 @@ static long __video_do_ioctl(struct file *file, | |||
1135 | { | 1141 | { |
1136 | struct v4l2_input *p = arg; | 1142 | struct v4l2_input *p = arg; |
1137 | 1143 | ||
1144 | /* | ||
1145 | * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & | ||
1146 | * CAP_STD here based on ioctl handler provided by the | ||
1147 | * driver. If the driver doesn't support these | ||
1148 | * for a specific input, it must override these flags. | ||
1149 | */ | ||
1150 | if (ops->vidioc_s_std) | ||
1151 | p->capabilities |= V4L2_IN_CAP_STD; | ||
1152 | if (ops->vidioc_s_dv_preset) | ||
1153 | p->capabilities |= V4L2_IN_CAP_PRESETS; | ||
1154 | if (ops->vidioc_s_dv_timings) | ||
1155 | p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS; | ||
1156 | |||
1138 | if (!ops->vidioc_enum_input) | 1157 | if (!ops->vidioc_enum_input) |
1139 | break; | 1158 | break; |
1140 | 1159 | ||
@@ -1179,6 +1198,19 @@ static long __video_do_ioctl(struct file *file, | |||
1179 | if (!ops->vidioc_enum_output) | 1198 | if (!ops->vidioc_enum_output) |
1180 | break; | 1199 | break; |
1181 | 1200 | ||
1201 | /* | ||
1202 | * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & | ||
1203 | * CAP_STD here based on ioctl handler provided by the | ||
1204 | * driver. If the driver doesn't support these | ||
1205 | * for a specific output, it must override these flags. | ||
1206 | */ | ||
1207 | if (ops->vidioc_s_std) | ||
1208 | p->capabilities |= V4L2_OUT_CAP_STD; | ||
1209 | if (ops->vidioc_s_dv_preset) | ||
1210 | p->capabilities |= V4L2_OUT_CAP_PRESETS; | ||
1211 | if (ops->vidioc_s_dv_timings) | ||
1212 | p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS; | ||
1213 | |||
1182 | ret = ops->vidioc_enum_output(file, fh, p); | 1214 | ret = ops->vidioc_enum_output(file, fh, p); |
1183 | if (!ret) | 1215 | if (!ret) |
1184 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | 1216 | dbgarg(cmd, "index=%d, name=%s, type=%d, " |
@@ -1794,6 +1826,121 @@ static long __video_do_ioctl(struct file *file, | |||
1794 | } | 1826 | } |
1795 | break; | 1827 | break; |
1796 | } | 1828 | } |
1829 | case VIDIOC_ENUM_DV_PRESETS: | ||
1830 | { | ||
1831 | struct v4l2_dv_enum_preset *p = arg; | ||
1832 | |||
1833 | if (!ops->vidioc_enum_dv_presets) | ||
1834 | break; | ||
1835 | |||
1836 | ret = ops->vidioc_enum_dv_presets(file, fh, p); | ||
1837 | if (!ret) | ||
1838 | dbgarg(cmd, | ||
1839 | "index=%d, preset=%d, name=%s, width=%d," | ||
1840 | " height=%d ", | ||
1841 | p->index, p->preset, p->name, p->width, | ||
1842 | p->height); | ||
1843 | break; | ||
1844 | } | ||
1845 | case VIDIOC_S_DV_PRESET: | ||
1846 | { | ||
1847 | struct v4l2_dv_preset *p = arg; | ||
1848 | |||
1849 | if (!ops->vidioc_s_dv_preset) | ||
1850 | break; | ||
1851 | |||
1852 | dbgarg(cmd, "preset=%d\n", p->preset); | ||
1853 | ret = ops->vidioc_s_dv_preset(file, fh, p); | ||
1854 | break; | ||
1855 | } | ||
1856 | case VIDIOC_G_DV_PRESET: | ||
1857 | { | ||
1858 | struct v4l2_dv_preset *p = arg; | ||
1859 | |||
1860 | if (!ops->vidioc_g_dv_preset) | ||
1861 | break; | ||
1862 | |||
1863 | ret = ops->vidioc_g_dv_preset(file, fh, p); | ||
1864 | if (!ret) | ||
1865 | dbgarg(cmd, "preset=%d\n", p->preset); | ||
1866 | break; | ||
1867 | } | ||
1868 | case VIDIOC_QUERY_DV_PRESET: | ||
1869 | { | ||
1870 | struct v4l2_dv_preset *p = arg; | ||
1871 | |||
1872 | if (!ops->vidioc_query_dv_preset) | ||
1873 | break; | ||
1874 | |||
1875 | ret = ops->vidioc_query_dv_preset(file, fh, p); | ||
1876 | if (!ret) | ||
1877 | dbgarg(cmd, "preset=%d\n", p->preset); | ||
1878 | break; | ||
1879 | } | ||
1880 | case VIDIOC_S_DV_TIMINGS: | ||
1881 | { | ||
1882 | struct v4l2_dv_timings *p = arg; | ||
1883 | |||
1884 | if (!ops->vidioc_s_dv_timings) | ||
1885 | break; | ||
1886 | |||
1887 | switch (p->type) { | ||
1888 | case V4L2_DV_BT_656_1120: | ||
1889 | dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld," | ||
1890 | " width=%d, height=%d, polarities=%x," | ||
1891 | " hfrontporch=%d, hsync=%d, hbackporch=%d," | ||
1892 | " vfrontporch=%d, vsync=%d, vbackporch=%d," | ||
1893 | " il_vfrontporch=%d, il_vsync=%d," | ||
1894 | " il_vbackporch=%d\n", | ||
1895 | p->bt.interlaced, p->bt.pixelclock, | ||
1896 | p->bt.width, p->bt.height, p->bt.polarities, | ||
1897 | p->bt.hfrontporch, p->bt.hsync, | ||
1898 | p->bt.hbackporch, p->bt.vfrontporch, | ||
1899 | p->bt.vsync, p->bt.vbackporch, | ||
1900 | p->bt.il_vfrontporch, p->bt.il_vsync, | ||
1901 | p->bt.il_vbackporch); | ||
1902 | ret = ops->vidioc_s_dv_timings(file, fh, p); | ||
1903 | break; | ||
1904 | default: | ||
1905 | dbgarg2("Unknown type %d!\n", p->type); | ||
1906 | break; | ||
1907 | } | ||
1908 | break; | ||
1909 | } | ||
1910 | case VIDIOC_G_DV_TIMINGS: | ||
1911 | { | ||
1912 | struct v4l2_dv_timings *p = arg; | ||
1913 | |||
1914 | if (!ops->vidioc_g_dv_timings) | ||
1915 | break; | ||
1916 | |||
1917 | ret = ops->vidioc_g_dv_timings(file, fh, p); | ||
1918 | if (!ret) { | ||
1919 | switch (p->type) { | ||
1920 | case V4L2_DV_BT_656_1120: | ||
1921 | dbgarg2("bt-656/1120:interlaced=%d," | ||
1922 | " pixelclock=%lld," | ||
1923 | " width=%d, height=%d, polarities=%x," | ||
1924 | " hfrontporch=%d, hsync=%d," | ||
1925 | " hbackporch=%d, vfrontporch=%d," | ||
1926 | " vsync=%d, vbackporch=%d," | ||
1927 | " il_vfrontporch=%d, il_vsync=%d," | ||
1928 | " il_vbackporch=%d\n", | ||
1929 | p->bt.interlaced, p->bt.pixelclock, | ||
1930 | p->bt.width, p->bt.height, | ||
1931 | p->bt.polarities, p->bt.hfrontporch, | ||
1932 | p->bt.hsync, p->bt.hbackporch, | ||
1933 | p->bt.vfrontporch, p->bt.vsync, | ||
1934 | p->bt.vbackporch, p->bt.il_vfrontporch, | ||
1935 | p->bt.il_vsync, p->bt.il_vbackporch); | ||
1936 | break; | ||
1937 | default: | ||
1938 | dbgarg2("Unknown type %d!\n", p->type); | ||
1939 | break; | ||
1940 | } | ||
1941 | } | ||
1942 | break; | ||
1943 | } | ||
1797 | 1944 | ||
1798 | default: | 1945 | default: |
1799 | { | 1946 | { |
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index d25f28461da1..22c01097e8a8 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c | |||
@@ -141,9 +141,11 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, | |||
141 | struct vm_area_struct *vma; | 141 | struct vm_area_struct *vma; |
142 | unsigned long prev_pfn, this_pfn; | 142 | unsigned long prev_pfn, this_pfn; |
143 | unsigned long pages_done, user_address; | 143 | unsigned long pages_done, user_address; |
144 | unsigned int offset; | ||
144 | int ret; | 145 | int ret; |
145 | 146 | ||
146 | mem->size = PAGE_ALIGN(vb->size); | 147 | offset = vb->baddr & ~PAGE_MASK; |
148 | mem->size = PAGE_ALIGN(vb->size + offset); | ||
147 | mem->is_userptr = 0; | 149 | mem->is_userptr = 0; |
148 | ret = -EINVAL; | 150 | ret = -EINVAL; |
149 | 151 | ||
@@ -166,7 +168,7 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, | |||
166 | break; | 168 | break; |
167 | 169 | ||
168 | if (pages_done == 0) | 170 | if (pages_done == 0) |
169 | mem->dma_handle = this_pfn << PAGE_SHIFT; | 171 | mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; |
170 | else if (this_pfn != (prev_pfn + 1)) | 172 | else if (this_pfn != (prev_pfn + 1)) |
171 | ret = -EFAULT; | 173 | ret = -EFAULT; |
172 | 174 | ||
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index b034a81d2b1c..a15d1e7cbed8 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c | |||
@@ -4068,7 +4068,6 @@ static struct video_device vdev_template = { | |||
4068 | .fops = &vino_fops, | 4068 | .fops = &vino_fops, |
4069 | .ioctl_ops = &vino_ioctl_ops, | 4069 | .ioctl_ops = &vino_ioctl_ops, |
4070 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, | 4070 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, |
4071 | .minor = -1, | ||
4072 | }; | 4071 | }; |
4073 | 4072 | ||
4074 | static void vino_module_cleanup(int stage) | 4073 | static void vino_module_cleanup(int stage) |
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7705fc6baf00..37632a064966 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
@@ -1148,7 +1148,8 @@ static int vivi_open(struct file *file) | |||
1148 | return -EBUSY; | 1148 | return -EBUSY; |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num, | 1151 | dprintk(dev, 1, "open %s type=%s users=%d\n", |
1152 | video_device_node_name(dev->vfd), | ||
1152 | v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); | 1153 | v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); |
1153 | 1154 | ||
1154 | /* allocate + initialize per filehandle data */ | 1155 | /* allocate + initialize per filehandle data */ |
@@ -1221,8 +1222,7 @@ static int vivi_close(struct file *file) | |||
1221 | struct vivi_fh *fh = file->private_data; | 1222 | struct vivi_fh *fh = file->private_data; |
1222 | struct vivi_dev *dev = fh->dev; | 1223 | struct vivi_dev *dev = fh->dev; |
1223 | struct vivi_dmaqueue *vidq = &dev->vidq; | 1224 | struct vivi_dmaqueue *vidq = &dev->vidq; |
1224 | 1225 | struct video_device *vdev = video_devdata(file); | |
1225 | int minor = video_devdata(file)->minor; | ||
1226 | 1226 | ||
1227 | vivi_stop_thread(vidq); | 1227 | vivi_stop_thread(vidq); |
1228 | videobuf_stop(&fh->vb_vidq); | 1228 | videobuf_stop(&fh->vb_vidq); |
@@ -1234,8 +1234,8 @@ static int vivi_close(struct file *file) | |||
1234 | dev->users--; | 1234 | dev->users--; |
1235 | mutex_unlock(&dev->mutex); | 1235 | mutex_unlock(&dev->mutex); |
1236 | 1236 | ||
1237 | dprintk(dev, 1, "close called (minor=%d, users=%d)\n", | 1237 | dprintk(dev, 1, "close called (dev=%s, users=%d)\n", |
1238 | minor, dev->users); | 1238 | video_device_node_name(vdev), dev->users); |
1239 | 1239 | ||
1240 | return 0; | 1240 | return 0; |
1241 | } | 1241 | } |
@@ -1296,7 +1296,6 @@ static struct video_device vivi_template = { | |||
1296 | .name = "vivi", | 1296 | .name = "vivi", |
1297 | .fops = &vivi_fops, | 1297 | .fops = &vivi_fops, |
1298 | .ioctl_ops = &vivi_ioctl_ops, | 1298 | .ioctl_ops = &vivi_ioctl_ops, |
1299 | .minor = -1, | ||
1300 | .release = video_device_release, | 1299 | .release = video_device_release, |
1301 | 1300 | ||
1302 | .tvnorms = V4L2_STD_525_60, | 1301 | .tvnorms = V4L2_STD_525_60, |
@@ -1317,8 +1316,8 @@ static int vivi_release(void) | |||
1317 | list_del(list); | 1316 | list_del(list); |
1318 | dev = list_entry(list, struct vivi_dev, vivi_devlist); | 1317 | dev = list_entry(list, struct vivi_dev, vivi_devlist); |
1319 | 1318 | ||
1320 | v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n", | 1319 | v4l2_info(&dev->v4l2_dev, "unregistering %s\n", |
1321 | dev->vfd->num); | 1320 | video_device_node_name(dev->vfd)); |
1322 | video_unregister_device(dev->vfd); | 1321 | video_unregister_device(dev->vfd); |
1323 | v4l2_device_unregister(&dev->v4l2_dev); | 1322 | v4l2_device_unregister(&dev->v4l2_dev); |
1324 | kfree(dev); | 1323 | kfree(dev); |
@@ -1372,15 +1371,12 @@ static int __init vivi_create_instance(int inst) | |||
1372 | /* Now that everything is fine, let's add it to device list */ | 1371 | /* Now that everything is fine, let's add it to device list */ |
1373 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); | 1372 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); |
1374 | 1373 | ||
1375 | snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", | ||
1376 | vivi_template.name, vfd->num); | ||
1377 | |||
1378 | if (video_nr >= 0) | 1374 | if (video_nr >= 0) |
1379 | video_nr++; | 1375 | video_nr++; |
1380 | 1376 | ||
1381 | dev->vfd = vfd; | 1377 | dev->vfd = vfd; |
1382 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n", | 1378 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", |
1383 | vfd->num); | 1379 | video_device_node_name(vfd)); |
1384 | return 0; | 1380 | return 0; |
1385 | 1381 | ||
1386 | rel_vdev: | 1382 | rel_vdev: |
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 37fcdc447db5..d807eea91757 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c | |||
@@ -2323,9 +2323,9 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam) | |||
2323 | error: | 2323 | error: |
2324 | cam->sensor_initialized = 0; | 2324 | cam->sensor_initialized = 0; |
2325 | cam->sensor = CC_UNKNOWN; | 2325 | cam->sensor = CC_UNKNOWN; |
2326 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " | 2326 | DBG(1, "Image sensor initialization failed for %s (%s). " |
2327 | "Try to detach and attach this device again", | 2327 | "Try to detach and attach this device again", |
2328 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2328 | symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev)) |
2329 | return err; | 2329 | return err; |
2330 | } | 2330 | } |
2331 | 2331 | ||
@@ -2571,7 +2571,8 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) | |||
2571 | { | 2571 | { |
2572 | mutex_lock(&w9968cf_devlist_mutex); | 2572 | mutex_lock(&w9968cf_devlist_mutex); |
2573 | 2573 | ||
2574 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num) | 2574 | DBG(2, "V4L device deregistered: %s", |
2575 | video_device_node_name(cam->v4ldev)) | ||
2575 | 2576 | ||
2576 | video_unregister_device(cam->v4ldev); | 2577 | video_unregister_device(cam->v4ldev); |
2577 | list_del(&cam->v4llist); | 2578 | list_del(&cam->v4llist); |
@@ -2605,17 +2606,19 @@ static int w9968cf_open(struct file *filp) | |||
2605 | 2606 | ||
2606 | if (cam->sensor == CC_UNKNOWN) { | 2607 | if (cam->sensor == CC_UNKNOWN) { |
2607 | DBG(2, "No supported image sensor has been detected by the " | 2608 | DBG(2, "No supported image sensor has been detected by the " |
2608 | "'ovcamchip' module for the %s (/dev/video%d). Make " | 2609 | "'ovcamchip' module for the %s (%s). Make sure " |
2609 | "sure it is loaded *before* (re)connecting the camera.", | 2610 | "it is loaded *before* (re)connecting the camera.", |
2610 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2611 | symbolic(camlist, cam->id), |
2612 | video_device_node_name(cam->v4ldev)) | ||
2611 | mutex_unlock(&cam->dev_mutex); | 2613 | mutex_unlock(&cam->dev_mutex); |
2612 | up_read(&w9968cf_disconnect); | 2614 | up_read(&w9968cf_disconnect); |
2613 | return -ENODEV; | 2615 | return -ENODEV; |
2614 | } | 2616 | } |
2615 | 2617 | ||
2616 | if (cam->users) { | 2618 | if (cam->users) { |
2617 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | 2619 | DBG(2, "%s (%s) has been already occupied by '%s'", |
2618 | symbolic(camlist, cam->id), cam->v4ldev->num, cam->command) | 2620 | symbolic(camlist, cam->id), |
2621 | video_device_node_name(cam->v4ldev), cam->command) | ||
2619 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | 2622 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { |
2620 | mutex_unlock(&cam->dev_mutex); | 2623 | mutex_unlock(&cam->dev_mutex); |
2621 | up_read(&w9968cf_disconnect); | 2624 | up_read(&w9968cf_disconnect); |
@@ -2636,8 +2639,8 @@ static int w9968cf_open(struct file *filp) | |||
2636 | mutex_lock(&cam->dev_mutex); | 2639 | mutex_lock(&cam->dev_mutex); |
2637 | } | 2640 | } |
2638 | 2641 | ||
2639 | DBG(5, "Opening '%s', /dev/video%d ...", | 2642 | DBG(5, "Opening '%s', %s ...", |
2640 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2643 | symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev)) |
2641 | 2644 | ||
2642 | cam->streaming = 0; | 2645 | cam->streaming = 0; |
2643 | cam->misconfigured = 0; | 2646 | cam->misconfigured = 0; |
@@ -2874,8 +2877,7 @@ static long w9968cf_v4l_ioctl(struct file *filp, | |||
2874 | .minwidth = cam->minwidth, | 2877 | .minwidth = cam->minwidth, |
2875 | .minheight = cam->minheight, | 2878 | .minheight = cam->minheight, |
2876 | }; | 2879 | }; |
2877 | sprintf(cap.name, "W996[87]CF USB Camera #%d", | 2880 | sprintf(cap.name, "W996[87]CF USB Camera"); |
2878 | cam->v4ldev->num); | ||
2879 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) | 2881 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) |
2880 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | 2882 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) |
2881 | : cam->maxwidth; | 2883 | : cam->maxwidth; |
@@ -3485,7 +3487,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3485 | 3487 | ||
3486 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); | 3488 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); |
3487 | cam->v4ldev->fops = &w9968cf_fops; | 3489 | cam->v4ldev->fops = &w9968cf_fops; |
3488 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
3489 | cam->v4ldev->release = video_device_release; | 3490 | cam->v4ldev->release = video_device_release; |
3490 | video_set_drvdata(cam->v4ldev, cam); | 3491 | video_set_drvdata(cam->v4ldev, cam); |
3491 | cam->v4ldev->v4l2_dev = &cam->v4l2_dev; | 3492 | cam->v4ldev->v4l2_dev = &cam->v4l2_dev; |
@@ -3501,7 +3502,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3501 | goto fail; | 3502 | goto fail; |
3502 | } | 3503 | } |
3503 | 3504 | ||
3504 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num) | 3505 | DBG(2, "V4L device registered as %s", |
3506 | video_device_node_name(cam->v4ldev)) | ||
3505 | 3507 | ||
3506 | /* Set some basic constants */ | 3508 | /* Set some basic constants */ |
3507 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | 3509 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); |
@@ -3557,10 +3559,10 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) | |||
3557 | wake_up_interruptible_all(&cam->open); | 3559 | wake_up_interruptible_all(&cam->open); |
3558 | 3560 | ||
3559 | if (cam->users) { | 3561 | if (cam->users) { |
3560 | DBG(2, "The device is open (/dev/video%d)! " | 3562 | DBG(2, "The device is open (%s)! " |
3561 | "Process name: %s. Deregistration and memory " | 3563 | "Process name: %s. Deregistration and memory " |
3562 | "deallocation are deferred on close.", | 3564 | "deallocation are deferred on close.", |
3563 | cam->v4ldev->num, cam->command) | 3565 | video_device_node_name(cam->v4ldev), cam->command) |
3564 | cam->misconfigured = 1; | 3566 | cam->misconfigured = 1; |
3565 | w9968cf_stop_transfer(cam); | 3567 | w9968cf_stop_transfer(cam); |
3566 | wake_up_interruptible(&cam->wait_queue); | 3568 | wake_up_interruptible(&cam->wait_queue); |
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 312a71336fd0..e44e4b5f3e50 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c | |||
@@ -538,8 +538,8 @@ static int zc0301_stream_interrupt(struct zc0301_device* cam) | |||
538 | else if (cam->stream != STREAM_OFF) { | 538 | else if (cam->stream != STREAM_OFF) { |
539 | cam->state |= DEV_MISCONFIGURED; | 539 | cam->state |= DEV_MISCONFIGURED; |
540 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | 540 | DBG(1, "URB timeout reached. The camera is misconfigured. To " |
541 | "use it, close and open /dev/video%d again.", | 541 | "use it, close and open %s again.", |
542 | cam->v4ldev->num); | 542 | video_device_node_name(cam->v4ldev)); |
543 | return -EIO; | 543 | return -EIO; |
544 | } | 544 | } |
545 | 545 | ||
@@ -640,7 +640,8 @@ static void zc0301_release_resources(struct kref *kref) | |||
640 | { | 640 | { |
641 | struct zc0301_device *cam = container_of(kref, struct zc0301_device, | 641 | struct zc0301_device *cam = container_of(kref, struct zc0301_device, |
642 | kref); | 642 | kref); |
643 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); | 643 | DBG(2, "V4L2 device %s deregistered", |
644 | video_device_node_name(cam->v4ldev)); | ||
644 | video_set_drvdata(cam->v4ldev, NULL); | 645 | video_set_drvdata(cam->v4ldev, NULL); |
645 | video_unregister_device(cam->v4ldev); | 646 | video_unregister_device(cam->v4ldev); |
646 | usb_put_dev(cam->usbdev); | 647 | usb_put_dev(cam->usbdev); |
@@ -679,7 +680,8 @@ static int zc0301_open(struct file *filp) | |||
679 | } | 680 | } |
680 | 681 | ||
681 | if (cam->users) { | 682 | if (cam->users) { |
682 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->num); | 683 | DBG(2, "Device %s is busy...", |
684 | video_device_node_name(cam->v4ldev)); | ||
683 | DBG(3, "Simultaneous opens are not supported"); | 685 | DBG(3, "Simultaneous opens are not supported"); |
684 | if ((filp->f_flags & O_NONBLOCK) || | 686 | if ((filp->f_flags & O_NONBLOCK) || |
685 | (filp->f_flags & O_NDELAY)) { | 687 | (filp->f_flags & O_NDELAY)) { |
@@ -722,7 +724,8 @@ static int zc0301_open(struct file *filp) | |||
722 | cam->frame_count = 0; | 724 | cam->frame_count = 0; |
723 | zc0301_empty_framequeues(cam); | 725 | zc0301_empty_framequeues(cam); |
724 | 726 | ||
725 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); | 727 | DBG(3, "Video device %s is open", |
728 | video_device_node_name(cam->v4ldev)); | ||
726 | 729 | ||
727 | out: | 730 | out: |
728 | mutex_unlock(&cam->open_mutex); | 731 | mutex_unlock(&cam->open_mutex); |
@@ -746,7 +749,8 @@ static int zc0301_release(struct file *filp) | |||
746 | cam->users--; | 749 | cam->users--; |
747 | wake_up_interruptible_nr(&cam->wait_open, 1); | 750 | wake_up_interruptible_nr(&cam->wait_open, 1); |
748 | 751 | ||
749 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); | 752 | DBG(3, "Video device %s closed", |
753 | video_device_node_name(cam->v4ldev)); | ||
750 | 754 | ||
751 | kref_put(&cam->kref, zc0301_release_resources); | 755 | kref_put(&cam->kref, zc0301_release_resources); |
752 | 756 | ||
@@ -1276,8 +1280,8 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) | |||
1276 | if (err) { /* atomic, no rollback in ioctl() */ | 1280 | if (err) { /* atomic, no rollback in ioctl() */ |
1277 | cam->state |= DEV_MISCONFIGURED; | 1281 | cam->state |= DEV_MISCONFIGURED; |
1278 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | 1282 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " |
1279 | "use the camera, close and open /dev/video%d again.", | 1283 | "use the camera, close and open %s again.", |
1280 | cam->v4ldev->num); | 1284 | video_device_node_name(cam->v4ldev)); |
1281 | return -EIO; | 1285 | return -EIO; |
1282 | } | 1286 | } |
1283 | 1287 | ||
@@ -1289,8 +1293,8 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) | |||
1289 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | 1293 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { |
1290 | cam->state |= DEV_MISCONFIGURED; | 1294 | cam->state |= DEV_MISCONFIGURED; |
1291 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | 1295 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " |
1292 | "use the camera, close and open /dev/video%d again.", | 1296 | "use the camera, close and open %s again.", |
1293 | cam->v4ldev->num); | 1297 | video_device_node_name(cam->v4ldev)); |
1294 | return -ENOMEM; | 1298 | return -ENOMEM; |
1295 | } | 1299 | } |
1296 | 1300 | ||
@@ -1471,8 +1475,8 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, | |||
1471 | if (err) { /* atomic, no rollback in ioctl() */ | 1475 | if (err) { /* atomic, no rollback in ioctl() */ |
1472 | cam->state |= DEV_MISCONFIGURED; | 1476 | cam->state |= DEV_MISCONFIGURED; |
1473 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | 1477 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " |
1474 | "use the camera, close and open /dev/video%d again.", | 1478 | "use the camera, close and open %s again.", |
1475 | cam->v4ldev->num); | 1479 | video_device_node_name(cam->v4ldev)); |
1476 | return -EIO; | 1480 | return -EIO; |
1477 | } | 1481 | } |
1478 | 1482 | ||
@@ -1483,8 +1487,8 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, | |||
1483 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | 1487 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { |
1484 | cam->state |= DEV_MISCONFIGURED; | 1488 | cam->state |= DEV_MISCONFIGURED; |
1485 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | 1489 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " |
1486 | "use the camera, close and open /dev/video%d again.", | 1490 | "use the camera, close and open %s again.", |
1487 | cam->v4ldev->num); | 1491 | video_device_node_name(cam->v4ldev)); |
1488 | return -ENOMEM; | 1492 | return -ENOMEM; |
1489 | } | 1493 | } |
1490 | 1494 | ||
@@ -1530,8 +1534,8 @@ zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) | |||
1530 | if (err) { /* atomic, no rollback in ioctl() */ | 1534 | if (err) { /* atomic, no rollback in ioctl() */ |
1531 | cam->state |= DEV_MISCONFIGURED; | 1535 | cam->state |= DEV_MISCONFIGURED; |
1532 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | 1536 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " |
1533 | "problems. To use the camera, close and open " | 1537 | "problems. To use the camera, close and open %s again.", |
1534 | "/dev/video%d again.", cam->v4ldev->num); | 1538 | video_device_node_name(cam->v4ldev)); |
1535 | return -EIO; | 1539 | return -EIO; |
1536 | } | 1540 | } |
1537 | 1541 | ||
@@ -1984,7 +1988,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
1984 | 1988 | ||
1985 | strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); | 1989 | strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); |
1986 | cam->v4ldev->fops = &zc0301_fops; | 1990 | cam->v4ldev->fops = &zc0301_fops; |
1987 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
1988 | cam->v4ldev->release = video_device_release; | 1991 | cam->v4ldev->release = video_device_release; |
1989 | cam->v4ldev->parent = &udev->dev; | 1992 | cam->v4ldev->parent = &udev->dev; |
1990 | video_set_drvdata(cam->v4ldev, cam); | 1993 | video_set_drvdata(cam->v4ldev, cam); |
@@ -2003,7 +2006,8 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
2003 | goto fail; | 2006 | goto fail; |
2004 | } | 2007 | } |
2005 | 2008 | ||
2006 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); | 2009 | DBG(2, "V4L2 device registered as %s", |
2010 | video_device_node_name(cam->v4ldev)); | ||
2007 | 2011 | ||
2008 | cam->module_param.force_munmap = force_munmap[dev_nr]; | 2012 | cam->module_param.force_munmap = force_munmap[dev_nr]; |
2009 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | 2013 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; |
@@ -2040,9 +2044,9 @@ static void zc0301_usb_disconnect(struct usb_interface* intf) | |||
2040 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | 2044 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); |
2041 | 2045 | ||
2042 | if (cam->users) { | 2046 | if (cam->users) { |
2043 | DBG(2, "Device /dev/video%d is open! Deregistration and " | 2047 | DBG(2, "Device %s is open! Deregistration and " |
2044 | "memory deallocation are deferred.", | 2048 | "memory deallocation are deferred.", |
2045 | cam->v4ldev->num); | 2049 | video_device_node_name(cam->v4ldev)); |
2046 | cam->state |= DEV_MISCONFIGURED; | 2050 | cam->state |= DEV_MISCONFIGURED; |
2047 | zc0301_stop_transfer(cam); | 2051 | zc0301_stop_transfer(cam); |
2048 | cam->state |= DEV_DISCONNECTED; | 2052 | cam->state |= DEV_DISCONNECTED; |
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index e9f72ca458f1..2ddffed019ee 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c | |||
@@ -3387,6 +3387,5 @@ struct video_device zoran_template __devinitdata = { | |||
3387 | .ioctl_ops = &zoran_ioctl_ops, | 3387 | .ioctl_ops = &zoran_ioctl_ops, |
3388 | .release = &zoran_vdev_release, | 3388 | .release = &zoran_vdev_release, |
3389 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, | 3389 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, |
3390 | .minor = -1 | ||
3391 | }; | 3390 | }; |
3392 | 3391 | ||
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 2ef110b5221b..f0eae83e3d89 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c | |||
@@ -1455,7 +1455,6 @@ static struct video_device zr364xx_template = { | |||
1455 | .fops = &zr364xx_fops, | 1455 | .fops = &zr364xx_fops, |
1456 | .ioctl_ops = &zr364xx_ioctl_ops, | 1456 | .ioctl_ops = &zr364xx_ioctl_ops, |
1457 | .release = video_device_release, | 1457 | .release = video_device_release, |
1458 | .minor = -1, | ||
1459 | }; | 1458 | }; |
1460 | 1459 | ||
1461 | 1460 | ||
@@ -1635,8 +1634,8 @@ static int zr364xx_probe(struct usb_interface *intf, | |||
1635 | 1634 | ||
1636 | spin_lock_init(&cam->slock); | 1635 | spin_lock_init(&cam->slock); |
1637 | 1636 | ||
1638 | dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n", | 1637 | dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", |
1639 | cam->vdev->num); | 1638 | video_device_node_name(cam->vdev)); |
1640 | return 0; | 1639 | return 0; |
1641 | } | 1640 | } |
1642 | 1641 | ||
diff --git a/drivers/misc/sgi-gru/gru.h b/drivers/misc/sgi-gru/gru.h index f93f03a9e6e9..3ad76cd18b4b 100644 --- a/drivers/misc/sgi-gru/gru.h +++ b/drivers/misc/sgi-gru/gru.h | |||
@@ -53,6 +53,17 @@ struct gru_chiplet_info { | |||
53 | int free_user_cbr; | 53 | int free_user_cbr; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | /* | ||
57 | * Statictics kept for each context. | ||
58 | */ | ||
59 | struct gru_gseg_statistics { | ||
60 | unsigned long fmm_tlbmiss; | ||
61 | unsigned long upm_tlbmiss; | ||
62 | unsigned long tlbdropin; | ||
63 | unsigned long context_stolen; | ||
64 | unsigned long reserved[10]; | ||
65 | }; | ||
66 | |||
56 | /* Flags for GRU options on the gru_create_context() call */ | 67 | /* Flags for GRU options on the gru_create_context() call */ |
57 | /* Select one of the follow 4 options to specify how TLB misses are handled */ | 68 | /* Select one of the follow 4 options to specify how TLB misses are handled */ |
58 | #define GRU_OPT_MISS_DEFAULT 0x0000 /* Use default mode */ | 69 | #define GRU_OPT_MISS_DEFAULT 0x0000 /* Use default mode */ |
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h index 3c9c06618e6a..d95587cc794c 100644 --- a/drivers/misc/sgi-gru/gru_instructions.h +++ b/drivers/misc/sgi-gru/gru_instructions.h | |||
@@ -34,17 +34,17 @@ extern void gru_wait_abort_proc(void *cb); | |||
34 | #include <asm/intrinsics.h> | 34 | #include <asm/intrinsics.h> |
35 | #define __flush_cache(p) ia64_fc((unsigned long)p) | 35 | #define __flush_cache(p) ia64_fc((unsigned long)p) |
36 | /* Use volatile on IA64 to ensure ordering via st4.rel */ | 36 | /* Use volatile on IA64 to ensure ordering via st4.rel */ |
37 | #define gru_ordered_store_int(p, v) \ | 37 | #define gru_ordered_store_ulong(p, v) \ |
38 | do { \ | 38 | do { \ |
39 | barrier(); \ | 39 | barrier(); \ |
40 | *((volatile int *)(p)) = v; /* force st.rel */ \ | 40 | *((volatile unsigned long *)(p)) = v; /* force st.rel */ \ |
41 | } while (0) | 41 | } while (0) |
42 | #elif defined(CONFIG_X86_64) | 42 | #elif defined(CONFIG_X86_64) |
43 | #define __flush_cache(p) clflush(p) | 43 | #define __flush_cache(p) clflush(p) |
44 | #define gru_ordered_store_int(p, v) \ | 44 | #define gru_ordered_store_ulong(p, v) \ |
45 | do { \ | 45 | do { \ |
46 | barrier(); \ | 46 | barrier(); \ |
47 | *(int *)p = v; \ | 47 | *(unsigned long *)p = v; \ |
48 | } while (0) | 48 | } while (0) |
49 | #else | 49 | #else |
50 | #error "Unsupported architecture" | 50 | #error "Unsupported architecture" |
@@ -129,8 +129,13 @@ struct gru_instruction_bits { | |||
129 | */ | 129 | */ |
130 | struct gru_instruction { | 130 | struct gru_instruction { |
131 | /* DW 0 */ | 131 | /* DW 0 */ |
132 | unsigned int op32; /* icmd,xtype,iaa0,ima,opc */ | 132 | union { |
133 | unsigned int tri0; | 133 | unsigned long op64; /* icmd,xtype,iaa0,ima,opc,tri0 */ |
134 | struct { | ||
135 | unsigned int op32; | ||
136 | unsigned int tri0; | ||
137 | }; | ||
138 | }; | ||
134 | unsigned long tri1_bufsize; /* DW 1 */ | 139 | unsigned long tri1_bufsize; /* DW 1 */ |
135 | unsigned long baddr0; /* DW 2 */ | 140 | unsigned long baddr0; /* DW 2 */ |
136 | unsigned long nelem; /* DW 3 */ | 141 | unsigned long nelem; /* DW 3 */ |
@@ -140,7 +145,7 @@ struct gru_instruction { | |||
140 | unsigned long avalue; /* DW 7 */ | 145 | unsigned long avalue; /* DW 7 */ |
141 | }; | 146 | }; |
142 | 147 | ||
143 | /* Some shifts and masks for the low 32 bits of a GRU command */ | 148 | /* Some shifts and masks for the low 64 bits of a GRU command */ |
144 | #define GRU_CB_ICMD_SHFT 0 | 149 | #define GRU_CB_ICMD_SHFT 0 |
145 | #define GRU_CB_ICMD_MASK 0x1 | 150 | #define GRU_CB_ICMD_MASK 0x1 |
146 | #define GRU_CB_XTYPE_SHFT 8 | 151 | #define GRU_CB_XTYPE_SHFT 8 |
@@ -155,6 +160,10 @@ struct gru_instruction { | |||
155 | #define GRU_CB_OPC_MASK 0xff | 160 | #define GRU_CB_OPC_MASK 0xff |
156 | #define GRU_CB_EXOPC_SHFT 24 | 161 | #define GRU_CB_EXOPC_SHFT 24 |
157 | #define GRU_CB_EXOPC_MASK 0xff | 162 | #define GRU_CB_EXOPC_MASK 0xff |
163 | #define GRU_IDEF2_SHFT 32 | ||
164 | #define GRU_IDEF2_MASK 0x3ffff | ||
165 | #define GRU_ISTATUS_SHFT 56 | ||
166 | #define GRU_ISTATUS_MASK 0x3 | ||
158 | 167 | ||
159 | /* GRU instruction opcodes (opc field) */ | 168 | /* GRU instruction opcodes (opc field) */ |
160 | #define OP_NOP 0x00 | 169 | #define OP_NOP 0x00 |
@@ -256,6 +265,7 @@ struct gru_instruction { | |||
256 | #define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 16) | 265 | #define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 16) |
257 | #define CBE_CAUSE_RA_RESPONSE_DATA_ERROR (1 << 17) | 266 | #define CBE_CAUSE_RA_RESPONSE_DATA_ERROR (1 << 17) |
258 | #define CBE_CAUSE_HA_RESPONSE_DATA_ERROR (1 << 18) | 267 | #define CBE_CAUSE_HA_RESPONSE_DATA_ERROR (1 << 18) |
268 | #define CBE_CAUSE_FORCED_ERROR (1 << 19) | ||
259 | 269 | ||
260 | /* CBE cbrexecstatus bits */ | 270 | /* CBE cbrexecstatus bits */ |
261 | #define CBR_EXS_ABORT_OCC_BIT 0 | 271 | #define CBR_EXS_ABORT_OCC_BIT 0 |
@@ -264,13 +274,15 @@ struct gru_instruction { | |||
264 | #define CBR_EXS_QUEUED_BIT 3 | 274 | #define CBR_EXS_QUEUED_BIT 3 |
265 | #define CBR_EXS_TLB_INVAL_BIT 4 | 275 | #define CBR_EXS_TLB_INVAL_BIT 4 |
266 | #define CBR_EXS_EXCEPTION_BIT 5 | 276 | #define CBR_EXS_EXCEPTION_BIT 5 |
277 | #define CBR_EXS_CB_INT_PENDING_BIT 6 | ||
267 | 278 | ||
268 | #define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) | 279 | #define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) |
269 | #define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) | 280 | #define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) |
270 | #define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) | 281 | #define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) |
271 | #define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) | 282 | #define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) |
272 | #define CBR_TLB_INVAL (1 << CBR_EXS_TLB_INVAL_BIT) | 283 | #define CBR_EXS_TLB_INVAL (1 << CBR_EXS_TLB_INVAL_BIT) |
273 | #define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) | 284 | #define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) |
285 | #define CBR_EXS_CB_INT_PENDING (1 << CBR_EXS_CB_INT_PENDING_BIT) | ||
274 | 286 | ||
275 | /* | 287 | /* |
276 | * Exceptions are retried for the following cases. If any OTHER bits are set | 288 | * Exceptions are retried for the following cases. If any OTHER bits are set |
@@ -296,12 +308,14 @@ union gru_mesqhead { | |||
296 | 308 | ||
297 | 309 | ||
298 | /* Generate the low word of a GRU instruction */ | 310 | /* Generate the low word of a GRU instruction */ |
299 | static inline unsigned int | 311 | static inline unsigned long |
300 | __opword(unsigned char opcode, unsigned char exopc, unsigned char xtype, | 312 | __opdword(unsigned char opcode, unsigned char exopc, unsigned char xtype, |
301 | unsigned char iaa0, unsigned char iaa1, | 313 | unsigned char iaa0, unsigned char iaa1, |
302 | unsigned char ima) | 314 | unsigned long idef2, unsigned char ima) |
303 | { | 315 | { |
304 | return (1 << GRU_CB_ICMD_SHFT) | | 316 | return (1 << GRU_CB_ICMD_SHFT) | |
317 | ((unsigned long)CBS_ACTIVE << GRU_ISTATUS_SHFT) | | ||
318 | (idef2<< GRU_IDEF2_SHFT) | | ||
305 | (iaa0 << GRU_CB_IAA0_SHFT) | | 319 | (iaa0 << GRU_CB_IAA0_SHFT) | |
306 | (iaa1 << GRU_CB_IAA1_SHFT) | | 320 | (iaa1 << GRU_CB_IAA1_SHFT) | |
307 | (ima << GRU_CB_IMA_SHFT) | | 321 | (ima << GRU_CB_IMA_SHFT) | |
@@ -319,12 +333,13 @@ static inline void gru_flush_cache(void *p) | |||
319 | } | 333 | } |
320 | 334 | ||
321 | /* | 335 | /* |
322 | * Store the lower 32 bits of the command including the "start" bit. Then | 336 | * Store the lower 64 bits of the command including the "start" bit. Then |
323 | * start the instruction executing. | 337 | * start the instruction executing. |
324 | */ | 338 | */ |
325 | static inline void gru_start_instruction(struct gru_instruction *ins, int op32) | 339 | static inline void gru_start_instruction(struct gru_instruction *ins, unsigned long op64) |
326 | { | 340 | { |
327 | gru_ordered_store_int(ins, op32); | 341 | gru_ordered_store_ulong(ins, op64); |
342 | mb(); | ||
328 | gru_flush_cache(ins); | 343 | gru_flush_cache(ins); |
329 | } | 344 | } |
330 | 345 | ||
@@ -340,6 +355,30 @@ static inline void gru_start_instruction(struct gru_instruction *ins, int op32) | |||
340 | * - nelem and stride are in elements | 355 | * - nelem and stride are in elements |
341 | * - tri0/tri1 is in bytes for the beginning of the data segment. | 356 | * - tri0/tri1 is in bytes for the beginning of the data segment. |
342 | */ | 357 | */ |
358 | static inline void gru_vload_phys(void *cb, unsigned long gpa, | ||
359 | unsigned int tri0, int iaa, unsigned long hints) | ||
360 | { | ||
361 | struct gru_instruction *ins = (struct gru_instruction *)cb; | ||
362 | |||
363 | ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62); | ||
364 | ins->nelem = 1; | ||
365 | ins->op1_stride = 1; | ||
366 | gru_start_instruction(ins, __opdword(OP_VLOAD, 0, XTYPE_DW, iaa, 0, | ||
367 | (unsigned long)tri0, CB_IMA(hints))); | ||
368 | } | ||
369 | |||
370 | static inline void gru_vstore_phys(void *cb, unsigned long gpa, | ||
371 | unsigned int tri0, int iaa, unsigned long hints) | ||
372 | { | ||
373 | struct gru_instruction *ins = (struct gru_instruction *)cb; | ||
374 | |||
375 | ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62); | ||
376 | ins->nelem = 1; | ||
377 | ins->op1_stride = 1; | ||
378 | gru_start_instruction(ins, __opdword(OP_VSTORE, 0, XTYPE_DW, iaa, 0, | ||
379 | (unsigned long)tri0, CB_IMA(hints))); | ||
380 | } | ||
381 | |||
343 | static inline void gru_vload(void *cb, unsigned long mem_addr, | 382 | static inline void gru_vload(void *cb, unsigned long mem_addr, |
344 | unsigned int tri0, unsigned char xtype, unsigned long nelem, | 383 | unsigned int tri0, unsigned char xtype, unsigned long nelem, |
345 | unsigned long stride, unsigned long hints) | 384 | unsigned long stride, unsigned long hints) |
@@ -348,10 +387,9 @@ static inline void gru_vload(void *cb, unsigned long mem_addr, | |||
348 | 387 | ||
349 | ins->baddr0 = (long)mem_addr; | 388 | ins->baddr0 = (long)mem_addr; |
350 | ins->nelem = nelem; | 389 | ins->nelem = nelem; |
351 | ins->tri0 = tri0; | ||
352 | ins->op1_stride = stride; | 390 | ins->op1_stride = stride; |
353 | gru_start_instruction(ins, __opword(OP_VLOAD, 0, xtype, IAA_RAM, 0, | 391 | gru_start_instruction(ins, __opdword(OP_VLOAD, 0, xtype, IAA_RAM, 0, |
354 | CB_IMA(hints))); | 392 | (unsigned long)tri0, CB_IMA(hints))); |
355 | } | 393 | } |
356 | 394 | ||
357 | static inline void gru_vstore(void *cb, unsigned long mem_addr, | 395 | static inline void gru_vstore(void *cb, unsigned long mem_addr, |
@@ -362,10 +400,9 @@ static inline void gru_vstore(void *cb, unsigned long mem_addr, | |||
362 | 400 | ||
363 | ins->baddr0 = (long)mem_addr; | 401 | ins->baddr0 = (long)mem_addr; |
364 | ins->nelem = nelem; | 402 | ins->nelem = nelem; |
365 | ins->tri0 = tri0; | ||
366 | ins->op1_stride = stride; | 403 | ins->op1_stride = stride; |
367 | gru_start_instruction(ins, __opword(OP_VSTORE, 0, xtype, IAA_RAM, 0, | 404 | gru_start_instruction(ins, __opdword(OP_VSTORE, 0, xtype, IAA_RAM, 0, |
368 | CB_IMA(hints))); | 405 | tri0, CB_IMA(hints))); |
369 | } | 406 | } |
370 | 407 | ||
371 | static inline void gru_ivload(void *cb, unsigned long mem_addr, | 408 | static inline void gru_ivload(void *cb, unsigned long mem_addr, |
@@ -376,10 +413,9 @@ static inline void gru_ivload(void *cb, unsigned long mem_addr, | |||
376 | 413 | ||
377 | ins->baddr0 = (long)mem_addr; | 414 | ins->baddr0 = (long)mem_addr; |
378 | ins->nelem = nelem; | 415 | ins->nelem = nelem; |
379 | ins->tri0 = tri0; | ||
380 | ins->tri1_bufsize = tri1; | 416 | ins->tri1_bufsize = tri1; |
381 | gru_start_instruction(ins, __opword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, | 417 | gru_start_instruction(ins, __opdword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, |
382 | CB_IMA(hints))); | 418 | tri0, CB_IMA(hints))); |
383 | } | 419 | } |
384 | 420 | ||
385 | static inline void gru_ivstore(void *cb, unsigned long mem_addr, | 421 | static inline void gru_ivstore(void *cb, unsigned long mem_addr, |
@@ -390,10 +426,9 @@ static inline void gru_ivstore(void *cb, unsigned long mem_addr, | |||
390 | 426 | ||
391 | ins->baddr0 = (long)mem_addr; | 427 | ins->baddr0 = (long)mem_addr; |
392 | ins->nelem = nelem; | 428 | ins->nelem = nelem; |
393 | ins->tri0 = tri0; | ||
394 | ins->tri1_bufsize = tri1; | 429 | ins->tri1_bufsize = tri1; |
395 | gru_start_instruction(ins, __opword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, | 430 | gru_start_instruction(ins, __opdword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, |
396 | CB_IMA(hints))); | 431 | tri0, CB_IMA(hints))); |
397 | } | 432 | } |
398 | 433 | ||
399 | static inline void gru_vset(void *cb, unsigned long mem_addr, | 434 | static inline void gru_vset(void *cb, unsigned long mem_addr, |
@@ -406,8 +441,8 @@ static inline void gru_vset(void *cb, unsigned long mem_addr, | |||
406 | ins->op2_value_baddr1 = value; | 441 | ins->op2_value_baddr1 = value; |
407 | ins->nelem = nelem; | 442 | ins->nelem = nelem; |
408 | ins->op1_stride = stride; | 443 | ins->op1_stride = stride; |
409 | gru_start_instruction(ins, __opword(OP_VSET, 0, xtype, IAA_RAM, 0, | 444 | gru_start_instruction(ins, __opdword(OP_VSET, 0, xtype, IAA_RAM, 0, |
410 | CB_IMA(hints))); | 445 | 0, CB_IMA(hints))); |
411 | } | 446 | } |
412 | 447 | ||
413 | static inline void gru_ivset(void *cb, unsigned long mem_addr, | 448 | static inline void gru_ivset(void *cb, unsigned long mem_addr, |
@@ -420,8 +455,8 @@ static inline void gru_ivset(void *cb, unsigned long mem_addr, | |||
420 | ins->op2_value_baddr1 = value; | 455 | ins->op2_value_baddr1 = value; |
421 | ins->nelem = nelem; | 456 | ins->nelem = nelem; |
422 | ins->tri1_bufsize = tri1; | 457 | ins->tri1_bufsize = tri1; |
423 | gru_start_instruction(ins, __opword(OP_IVSET, 0, xtype, IAA_RAM, 0, | 458 | gru_start_instruction(ins, __opdword(OP_IVSET, 0, xtype, IAA_RAM, 0, |
424 | CB_IMA(hints))); | 459 | 0, CB_IMA(hints))); |
425 | } | 460 | } |
426 | 461 | ||
427 | static inline void gru_vflush(void *cb, unsigned long mem_addr, | 462 | static inline void gru_vflush(void *cb, unsigned long mem_addr, |
@@ -433,15 +468,15 @@ static inline void gru_vflush(void *cb, unsigned long mem_addr, | |||
433 | ins->baddr0 = (long)mem_addr; | 468 | ins->baddr0 = (long)mem_addr; |
434 | ins->op1_stride = stride; | 469 | ins->op1_stride = stride; |
435 | ins->nelem = nelem; | 470 | ins->nelem = nelem; |
436 | gru_start_instruction(ins, __opword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, | 471 | gru_start_instruction(ins, __opdword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, |
437 | CB_IMA(hints))); | 472 | 0, CB_IMA(hints))); |
438 | } | 473 | } |
439 | 474 | ||
440 | static inline void gru_nop(void *cb, int hints) | 475 | static inline void gru_nop(void *cb, int hints) |
441 | { | 476 | { |
442 | struct gru_instruction *ins = (void *)cb; | 477 | struct gru_instruction *ins = (void *)cb; |
443 | 478 | ||
444 | gru_start_instruction(ins, __opword(OP_NOP, 0, 0, 0, 0, CB_IMA(hints))); | 479 | gru_start_instruction(ins, __opdword(OP_NOP, 0, 0, 0, 0, 0, CB_IMA(hints))); |
445 | } | 480 | } |
446 | 481 | ||
447 | 482 | ||
@@ -455,10 +490,9 @@ static inline void gru_bcopy(void *cb, const unsigned long src, | |||
455 | ins->baddr0 = (long)src; | 490 | ins->baddr0 = (long)src; |
456 | ins->op2_value_baddr1 = (long)dest; | 491 | ins->op2_value_baddr1 = (long)dest; |
457 | ins->nelem = nelem; | 492 | ins->nelem = nelem; |
458 | ins->tri0 = tri0; | ||
459 | ins->tri1_bufsize = bufsize; | 493 | ins->tri1_bufsize = bufsize; |
460 | gru_start_instruction(ins, __opword(OP_BCOPY, 0, xtype, IAA_RAM, | 494 | gru_start_instruction(ins, __opdword(OP_BCOPY, 0, xtype, IAA_RAM, |
461 | IAA_RAM, CB_IMA(hints))); | 495 | IAA_RAM, tri0, CB_IMA(hints))); |
462 | } | 496 | } |
463 | 497 | ||
464 | static inline void gru_bstore(void *cb, const unsigned long src, | 498 | static inline void gru_bstore(void *cb, const unsigned long src, |
@@ -470,9 +504,8 @@ static inline void gru_bstore(void *cb, const unsigned long src, | |||
470 | ins->baddr0 = (long)src; | 504 | ins->baddr0 = (long)src; |
471 | ins->op2_value_baddr1 = (long)dest; | 505 | ins->op2_value_baddr1 = (long)dest; |
472 | ins->nelem = nelem; | 506 | ins->nelem = nelem; |
473 | ins->tri0 = tri0; | 507 | gru_start_instruction(ins, __opdword(OP_BSTORE, 0, xtype, 0, IAA_RAM, |
474 | gru_start_instruction(ins, __opword(OP_BSTORE, 0, xtype, 0, IAA_RAM, | 508 | tri0, CB_IMA(hints))); |
475 | CB_IMA(hints))); | ||
476 | } | 509 | } |
477 | 510 | ||
478 | static inline void gru_gamir(void *cb, int exopc, unsigned long src, | 511 | static inline void gru_gamir(void *cb, int exopc, unsigned long src, |
@@ -481,8 +514,8 @@ static inline void gru_gamir(void *cb, int exopc, unsigned long src, | |||
481 | struct gru_instruction *ins = (void *)cb; | 514 | struct gru_instruction *ins = (void *)cb; |
482 | 515 | ||
483 | ins->baddr0 = (long)src; | 516 | ins->baddr0 = (long)src; |
484 | gru_start_instruction(ins, __opword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, | 517 | gru_start_instruction(ins, __opdword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, |
485 | CB_IMA(hints))); | 518 | 0, CB_IMA(hints))); |
486 | } | 519 | } |
487 | 520 | ||
488 | static inline void gru_gamirr(void *cb, int exopc, unsigned long src, | 521 | static inline void gru_gamirr(void *cb, int exopc, unsigned long src, |
@@ -491,8 +524,8 @@ static inline void gru_gamirr(void *cb, int exopc, unsigned long src, | |||
491 | struct gru_instruction *ins = (void *)cb; | 524 | struct gru_instruction *ins = (void *)cb; |
492 | 525 | ||
493 | ins->baddr0 = (long)src; | 526 | ins->baddr0 = (long)src; |
494 | gru_start_instruction(ins, __opword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, | 527 | gru_start_instruction(ins, __opdword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, |
495 | CB_IMA(hints))); | 528 | 0, CB_IMA(hints))); |
496 | } | 529 | } |
497 | 530 | ||
498 | static inline void gru_gamer(void *cb, int exopc, unsigned long src, | 531 | static inline void gru_gamer(void *cb, int exopc, unsigned long src, |
@@ -505,8 +538,8 @@ static inline void gru_gamer(void *cb, int exopc, unsigned long src, | |||
505 | ins->baddr0 = (long)src; | 538 | ins->baddr0 = (long)src; |
506 | ins->op1_stride = operand1; | 539 | ins->op1_stride = operand1; |
507 | ins->op2_value_baddr1 = operand2; | 540 | ins->op2_value_baddr1 = operand2; |
508 | gru_start_instruction(ins, __opword(OP_GAMER, exopc, xtype, IAA_RAM, 0, | 541 | gru_start_instruction(ins, __opdword(OP_GAMER, exopc, xtype, IAA_RAM, 0, |
509 | CB_IMA(hints))); | 542 | 0, CB_IMA(hints))); |
510 | } | 543 | } |
511 | 544 | ||
512 | static inline void gru_gamerr(void *cb, int exopc, unsigned long src, | 545 | static inline void gru_gamerr(void *cb, int exopc, unsigned long src, |
@@ -518,8 +551,8 @@ static inline void gru_gamerr(void *cb, int exopc, unsigned long src, | |||
518 | ins->baddr0 = (long)src; | 551 | ins->baddr0 = (long)src; |
519 | ins->op1_stride = operand1; | 552 | ins->op1_stride = operand1; |
520 | ins->op2_value_baddr1 = operand2; | 553 | ins->op2_value_baddr1 = operand2; |
521 | gru_start_instruction(ins, __opword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, | 554 | gru_start_instruction(ins, __opdword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, |
522 | CB_IMA(hints))); | 555 | 0, CB_IMA(hints))); |
523 | } | 556 | } |
524 | 557 | ||
525 | static inline void gru_gamxr(void *cb, unsigned long src, | 558 | static inline void gru_gamxr(void *cb, unsigned long src, |
@@ -529,8 +562,8 @@ static inline void gru_gamxr(void *cb, unsigned long src, | |||
529 | 562 | ||
530 | ins->baddr0 = (long)src; | 563 | ins->baddr0 = (long)src; |
531 | ins->nelem = 4; | 564 | ins->nelem = 4; |
532 | gru_start_instruction(ins, __opword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, | 565 | gru_start_instruction(ins, __opdword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, |
533 | IAA_RAM, 0, CB_IMA(hints))); | 566 | IAA_RAM, 0, 0, CB_IMA(hints))); |
534 | } | 567 | } |
535 | 568 | ||
536 | static inline void gru_mesq(void *cb, unsigned long queue, | 569 | static inline void gru_mesq(void *cb, unsigned long queue, |
@@ -541,9 +574,8 @@ static inline void gru_mesq(void *cb, unsigned long queue, | |||
541 | 574 | ||
542 | ins->baddr0 = (long)queue; | 575 | ins->baddr0 = (long)queue; |
543 | ins->nelem = nelem; | 576 | ins->nelem = nelem; |
544 | ins->tri0 = tri0; | 577 | gru_start_instruction(ins, __opdword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, |
545 | gru_start_instruction(ins, __opword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, | 578 | tri0, CB_IMA(hints))); |
546 | CB_IMA(hints))); | ||
547 | } | 579 | } |
548 | 580 | ||
549 | static inline unsigned long gru_get_amo_value(void *cb) | 581 | static inline unsigned long gru_get_amo_value(void *cb) |
@@ -662,6 +694,14 @@ static inline void gru_wait_abort(void *cb) | |||
662 | gru_wait_abort_proc(cb); | 694 | gru_wait_abort_proc(cb); |
663 | } | 695 | } |
664 | 696 | ||
697 | /* | ||
698 | * Get a pointer to the start of a gseg | ||
699 | * p - Any valid pointer within the gseg | ||
700 | */ | ||
701 | static inline void *gru_get_gseg_pointer (void *p) | ||
702 | { | ||
703 | return (void *)((unsigned long)p & ~(GRU_GSEG_PAGESIZE - 1)); | ||
704 | } | ||
665 | 705 | ||
666 | /* | 706 | /* |
667 | * Get a pointer to a control block | 707 | * Get a pointer to a control block |
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 679e01778286..38657cdaf54d 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -40,6 +40,12 @@ | |||
40 | #include "gru_instructions.h" | 40 | #include "gru_instructions.h" |
41 | #include <asm/uv/uv_hub.h> | 41 | #include <asm/uv/uv_hub.h> |
42 | 42 | ||
43 | /* Return codes for vtop functions */ | ||
44 | #define VTOP_SUCCESS 0 | ||
45 | #define VTOP_INVALID -1 | ||
46 | #define VTOP_RETRY -2 | ||
47 | |||
48 | |||
43 | /* | 49 | /* |
44 | * Test if a physical address is a valid GRU GSEG address | 50 | * Test if a physical address is a valid GRU GSEG address |
45 | */ | 51 | */ |
@@ -90,19 +96,22 @@ static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr) | |||
90 | { | 96 | { |
91 | struct mm_struct *mm = current->mm; | 97 | struct mm_struct *mm = current->mm; |
92 | struct vm_area_struct *vma; | 98 | struct vm_area_struct *vma; |
93 | struct gru_thread_state *gts = NULL; | 99 | struct gru_thread_state *gts = ERR_PTR(-EINVAL); |
94 | 100 | ||
95 | down_write(&mm->mmap_sem); | 101 | down_write(&mm->mmap_sem); |
96 | vma = gru_find_vma(vaddr); | 102 | vma = gru_find_vma(vaddr); |
97 | if (vma) | 103 | if (!vma) |
98 | gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); | 104 | goto err; |
99 | if (gts) { | ||
100 | mutex_lock(>s->ts_ctxlock); | ||
101 | downgrade_write(&mm->mmap_sem); | ||
102 | } else { | ||
103 | up_write(&mm->mmap_sem); | ||
104 | } | ||
105 | 105 | ||
106 | gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); | ||
107 | if (IS_ERR(gts)) | ||
108 | goto err; | ||
109 | mutex_lock(>s->ts_ctxlock); | ||
110 | downgrade_write(&mm->mmap_sem); | ||
111 | return gts; | ||
112 | |||
113 | err: | ||
114 | up_write(&mm->mmap_sem); | ||
106 | return gts; | 115 | return gts; |
107 | } | 116 | } |
108 | 117 | ||
@@ -122,39 +131,15 @@ static void gru_unlock_gts(struct gru_thread_state *gts) | |||
122 | * is necessary to prevent the user from seeing a stale cb.istatus that will | 131 | * is necessary to prevent the user from seeing a stale cb.istatus that will |
123 | * change as soon as the TFH restart is complete. Races may cause an | 132 | * change as soon as the TFH restart is complete. Races may cause an |
124 | * occasional failure to clear the cb.istatus, but that is ok. | 133 | * occasional failure to clear the cb.istatus, but that is ok. |
125 | * | ||
126 | * If the cb address is not valid (should not happen, but...), nothing | ||
127 | * bad will happen.. The get_user()/put_user() will fail but there | ||
128 | * are no bad side-effects. | ||
129 | */ | 134 | */ |
130 | static void gru_cb_set_istatus_active(unsigned long __user *cb) | 135 | static void gru_cb_set_istatus_active(struct gru_instruction_bits *cbk) |
131 | { | 136 | { |
132 | union { | 137 | if (cbk) { |
133 | struct gru_instruction_bits bits; | 138 | cbk->istatus = CBS_ACTIVE; |
134 | unsigned long dw; | ||
135 | } u; | ||
136 | |||
137 | if (cb) { | ||
138 | get_user(u.dw, cb); | ||
139 | u.bits.istatus = CBS_ACTIVE; | ||
140 | put_user(u.dw, cb); | ||
141 | } | 139 | } |
142 | } | 140 | } |
143 | 141 | ||
144 | /* | 142 | /* |
145 | * Convert a interrupt IRQ to a pointer to the GRU GTS that caused the | ||
146 | * interrupt. Interrupts are always sent to a cpu on the blade that contains the | ||
147 | * GRU (except for headless blades which are not currently supported). A blade | ||
148 | * has N grus; a block of N consecutive IRQs is assigned to the GRUs. The IRQ | ||
149 | * number uniquely identifies the GRU chiplet on the local blade that caused the | ||
150 | * interrupt. Always called in interrupt context. | ||
151 | */ | ||
152 | static inline struct gru_state *irq_to_gru(int irq) | ||
153 | { | ||
154 | return &gru_base[uv_numa_blade_id()]->bs_grus[irq - IRQ_GRU]; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Read & clear a TFM | 143 | * Read & clear a TFM |
159 | * | 144 | * |
160 | * The GRU has an array of fault maps. A map is private to a cpu | 145 | * The GRU has an array of fault maps. A map is private to a cpu |
@@ -207,10 +192,11 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma, | |||
207 | { | 192 | { |
208 | struct page *page; | 193 | struct page *page; |
209 | 194 | ||
210 | /* ZZZ Need to handle HUGE pages */ | 195 | #ifdef CONFIG_HUGETLB_PAGE |
211 | if (is_vm_hugetlb_page(vma)) | 196 | *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT; |
212 | return -EFAULT; | 197 | #else |
213 | *pageshift = PAGE_SHIFT; | 198 | *pageshift = PAGE_SHIFT; |
199 | #endif | ||
214 | if (get_user_pages | 200 | if (get_user_pages |
215 | (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0) | 201 | (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0) |
216 | return -EFAULT; | 202 | return -EFAULT; |
@@ -268,7 +254,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, | |||
268 | return 0; | 254 | return 0; |
269 | 255 | ||
270 | err: | 256 | err: |
271 | local_irq_enable(); | ||
272 | return 1; | 257 | return 1; |
273 | } | 258 | } |
274 | 259 | ||
@@ -301,14 +286,69 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr, | |||
301 | paddr = paddr & ~((1UL << ps) - 1); | 286 | paddr = paddr & ~((1UL << ps) - 1); |
302 | *gpa = uv_soc_phys_ram_to_gpa(paddr); | 287 | *gpa = uv_soc_phys_ram_to_gpa(paddr); |
303 | *pageshift = ps; | 288 | *pageshift = ps; |
304 | return 0; | 289 | return VTOP_SUCCESS; |
305 | 290 | ||
306 | inval: | 291 | inval: |
307 | return -1; | 292 | return VTOP_INVALID; |
308 | upm: | 293 | upm: |
309 | return -2; | 294 | return VTOP_RETRY; |
295 | } | ||
296 | |||
297 | |||
298 | /* | ||
299 | * Flush a CBE from cache. The CBE is clean in the cache. Dirty the | ||
300 | * CBE cacheline so that the line will be written back to home agent. | ||
301 | * Otherwise the line may be silently dropped. This has no impact | ||
302 | * except on performance. | ||
303 | */ | ||
304 | static void gru_flush_cache_cbe(struct gru_control_block_extended *cbe) | ||
305 | { | ||
306 | if (unlikely(cbe)) { | ||
307 | cbe->cbrexecstatus = 0; /* make CL dirty */ | ||
308 | gru_flush_cache(cbe); | ||
309 | } | ||
310 | } | 310 | } |
311 | 311 | ||
312 | /* | ||
313 | * Preload the TLB with entries that may be required. Currently, preloading | ||
314 | * is implemented only for BCOPY. Preload <tlb_preload_count> pages OR to | ||
315 | * the end of the bcopy tranfer, whichever is smaller. | ||
316 | */ | ||
317 | static void gru_preload_tlb(struct gru_state *gru, | ||
318 | struct gru_thread_state *gts, int atomic, | ||
319 | unsigned long fault_vaddr, int asid, int write, | ||
320 | unsigned char tlb_preload_count, | ||
321 | struct gru_tlb_fault_handle *tfh, | ||
322 | struct gru_control_block_extended *cbe) | ||
323 | { | ||
324 | unsigned long vaddr = 0, gpa; | ||
325 | int ret, pageshift; | ||
326 | |||
327 | if (cbe->opccpy != OP_BCOPY) | ||
328 | return; | ||
329 | |||
330 | if (fault_vaddr == cbe->cbe_baddr0) | ||
331 | vaddr = fault_vaddr + GRU_CACHE_LINE_BYTES * cbe->cbe_src_cl - 1; | ||
332 | else if (fault_vaddr == cbe->cbe_baddr1) | ||
333 | vaddr = fault_vaddr + (1 << cbe->xtypecpy) * cbe->cbe_nelemcur - 1; | ||
334 | |||
335 | fault_vaddr &= PAGE_MASK; | ||
336 | vaddr &= PAGE_MASK; | ||
337 | vaddr = min(vaddr, fault_vaddr + tlb_preload_count * PAGE_SIZE); | ||
338 | |||
339 | while (vaddr > fault_vaddr) { | ||
340 | ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift); | ||
341 | if (ret || tfh_write_only(tfh, gpa, GAA_RAM, vaddr, asid, write, | ||
342 | GRU_PAGESIZE(pageshift))) | ||
343 | return; | ||
344 | gru_dbg(grudev, | ||
345 | "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, rw %d, ps %d, gpa 0x%lx\n", | ||
346 | atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh, | ||
347 | vaddr, asid, write, pageshift, gpa); | ||
348 | vaddr -= PAGE_SIZE; | ||
349 | STAT(tlb_preload_page); | ||
350 | } | ||
351 | } | ||
312 | 352 | ||
313 | /* | 353 | /* |
314 | * Drop a TLB entry into the GRU. The fault is described by info in an TFH. | 354 | * Drop a TLB entry into the GRU. The fault is described by info in an TFH. |
@@ -320,11 +360,14 @@ upm: | |||
320 | * < 0 = error code | 360 | * < 0 = error code |
321 | * | 361 | * |
322 | */ | 362 | */ |
323 | static int gru_try_dropin(struct gru_thread_state *gts, | 363 | static int gru_try_dropin(struct gru_state *gru, |
364 | struct gru_thread_state *gts, | ||
324 | struct gru_tlb_fault_handle *tfh, | 365 | struct gru_tlb_fault_handle *tfh, |
325 | unsigned long __user *cb) | 366 | struct gru_instruction_bits *cbk) |
326 | { | 367 | { |
327 | int pageshift = 0, asid, write, ret, atomic = !cb; | 368 | struct gru_control_block_extended *cbe = NULL; |
369 | unsigned char tlb_preload_count = gts->ts_tlb_preload_count; | ||
370 | int pageshift = 0, asid, write, ret, atomic = !cbk, indexway; | ||
328 | unsigned long gpa = 0, vaddr = 0; | 371 | unsigned long gpa = 0, vaddr = 0; |
329 | 372 | ||
330 | /* | 373 | /* |
@@ -335,24 +378,34 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
335 | */ | 378 | */ |
336 | 379 | ||
337 | /* | 380 | /* |
381 | * Prefetch the CBE if doing TLB preloading | ||
382 | */ | ||
383 | if (unlikely(tlb_preload_count)) { | ||
384 | cbe = gru_tfh_to_cbe(tfh); | ||
385 | prefetchw(cbe); | ||
386 | } | ||
387 | |||
388 | /* | ||
338 | * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call. | 389 | * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call. |
339 | * Might be a hardware race OR a stupid user. Ignore FMM because FMM | 390 | * Might be a hardware race OR a stupid user. Ignore FMM because FMM |
340 | * is a transient state. | 391 | * is a transient state. |
341 | */ | 392 | */ |
342 | if (tfh->status != TFHSTATUS_EXCEPTION) { | 393 | if (tfh->status != TFHSTATUS_EXCEPTION) { |
343 | gru_flush_cache(tfh); | 394 | gru_flush_cache(tfh); |
395 | sync_core(); | ||
344 | if (tfh->status != TFHSTATUS_EXCEPTION) | 396 | if (tfh->status != TFHSTATUS_EXCEPTION) |
345 | goto failnoexception; | 397 | goto failnoexception; |
346 | STAT(tfh_stale_on_fault); | 398 | STAT(tfh_stale_on_fault); |
347 | } | 399 | } |
348 | if (tfh->state == TFHSTATE_IDLE) | 400 | if (tfh->state == TFHSTATE_IDLE) |
349 | goto failidle; | 401 | goto failidle; |
350 | if (tfh->state == TFHSTATE_MISS_FMM && cb) | 402 | if (tfh->state == TFHSTATE_MISS_FMM && cbk) |
351 | goto failfmm; | 403 | goto failfmm; |
352 | 404 | ||
353 | write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; | 405 | write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; |
354 | vaddr = tfh->missvaddr; | 406 | vaddr = tfh->missvaddr; |
355 | asid = tfh->missasid; | 407 | asid = tfh->missasid; |
408 | indexway = tfh->indexway; | ||
356 | if (asid == 0) | 409 | if (asid == 0) |
357 | goto failnoasid; | 410 | goto failnoasid; |
358 | 411 | ||
@@ -366,41 +419,51 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
366 | goto failactive; | 419 | goto failactive; |
367 | 420 | ||
368 | ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift); | 421 | ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift); |
369 | if (ret == -1) | 422 | if (ret == VTOP_INVALID) |
370 | goto failinval; | 423 | goto failinval; |
371 | if (ret == -2) | 424 | if (ret == VTOP_RETRY) |
372 | goto failupm; | 425 | goto failupm; |
373 | 426 | ||
374 | if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) { | 427 | if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) { |
375 | gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift); | 428 | gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift); |
376 | if (atomic || !gru_update_cch(gts, 0)) { | 429 | if (atomic || !gru_update_cch(gts)) { |
377 | gts->ts_force_cch_reload = 1; | 430 | gts->ts_force_cch_reload = 1; |
378 | goto failupm; | 431 | goto failupm; |
379 | } | 432 | } |
380 | } | 433 | } |
381 | gru_cb_set_istatus_active(cb); | 434 | |
435 | if (unlikely(cbe) && pageshift == PAGE_SHIFT) { | ||
436 | gru_preload_tlb(gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe); | ||
437 | gru_flush_cache_cbe(cbe); | ||
438 | } | ||
439 | |||
440 | gru_cb_set_istatus_active(cbk); | ||
441 | gts->ustats.tlbdropin++; | ||
382 | tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, | 442 | tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, |
383 | GRU_PAGESIZE(pageshift)); | 443 | GRU_PAGESIZE(pageshift)); |
384 | STAT(tlb_dropin); | ||
385 | gru_dbg(grudev, | 444 | gru_dbg(grudev, |
386 | "%s: tfh 0x%p, vaddr 0x%lx, asid 0x%x, ps %d, gpa 0x%lx\n", | 445 | "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x," |
387 | ret ? "non-atomic" : "atomic", tfh, vaddr, asid, | 446 | " rw %d, ps %d, gpa 0x%lx\n", |
388 | pageshift, gpa); | 447 | atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh, vaddr, asid, |
448 | indexway, write, pageshift, gpa); | ||
449 | STAT(tlb_dropin); | ||
389 | return 0; | 450 | return 0; |
390 | 451 | ||
391 | failnoasid: | 452 | failnoasid: |
392 | /* No asid (delayed unload). */ | 453 | /* No asid (delayed unload). */ |
393 | STAT(tlb_dropin_fail_no_asid); | 454 | STAT(tlb_dropin_fail_no_asid); |
394 | gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | 455 | gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); |
395 | if (!cb) | 456 | if (!cbk) |
396 | tfh_user_polling_mode(tfh); | 457 | tfh_user_polling_mode(tfh); |
397 | else | 458 | else |
398 | gru_flush_cache(tfh); | 459 | gru_flush_cache(tfh); |
460 | gru_flush_cache_cbe(cbe); | ||
399 | return -EAGAIN; | 461 | return -EAGAIN; |
400 | 462 | ||
401 | failupm: | 463 | failupm: |
402 | /* Atomic failure switch CBR to UPM */ | 464 | /* Atomic failure switch CBR to UPM */ |
403 | tfh_user_polling_mode(tfh); | 465 | tfh_user_polling_mode(tfh); |
466 | gru_flush_cache_cbe(cbe); | ||
404 | STAT(tlb_dropin_fail_upm); | 467 | STAT(tlb_dropin_fail_upm); |
405 | gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | 468 | gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); |
406 | return 1; | 469 | return 1; |
@@ -408,6 +471,7 @@ failupm: | |||
408 | failfmm: | 471 | failfmm: |
409 | /* FMM state on UPM call */ | 472 | /* FMM state on UPM call */ |
410 | gru_flush_cache(tfh); | 473 | gru_flush_cache(tfh); |
474 | gru_flush_cache_cbe(cbe); | ||
411 | STAT(tlb_dropin_fail_fmm); | 475 | STAT(tlb_dropin_fail_fmm); |
412 | gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); | 476 | gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); |
413 | return 0; | 477 | return 0; |
@@ -415,17 +479,20 @@ failfmm: | |||
415 | failnoexception: | 479 | failnoexception: |
416 | /* TFH status did not show exception pending */ | 480 | /* TFH status did not show exception pending */ |
417 | gru_flush_cache(tfh); | 481 | gru_flush_cache(tfh); |
418 | if (cb) | 482 | gru_flush_cache_cbe(cbe); |
419 | gru_flush_cache(cb); | 483 | if (cbk) |
484 | gru_flush_cache(cbk); | ||
420 | STAT(tlb_dropin_fail_no_exception); | 485 | STAT(tlb_dropin_fail_no_exception); |
421 | gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state); | 486 | gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", |
487 | tfh, tfh->status, tfh->state); | ||
422 | return 0; | 488 | return 0; |
423 | 489 | ||
424 | failidle: | 490 | failidle: |
425 | /* TFH state was idle - no miss pending */ | 491 | /* TFH state was idle - no miss pending */ |
426 | gru_flush_cache(tfh); | 492 | gru_flush_cache(tfh); |
427 | if (cb) | 493 | gru_flush_cache_cbe(cbe); |
428 | gru_flush_cache(cb); | 494 | if (cbk) |
495 | gru_flush_cache(cbk); | ||
429 | STAT(tlb_dropin_fail_idle); | 496 | STAT(tlb_dropin_fail_idle); |
430 | gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); | 497 | gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); |
431 | return 0; | 498 | return 0; |
@@ -433,16 +500,18 @@ failidle: | |||
433 | failinval: | 500 | failinval: |
434 | /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ | 501 | /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ |
435 | tfh_exception(tfh); | 502 | tfh_exception(tfh); |
503 | gru_flush_cache_cbe(cbe); | ||
436 | STAT(tlb_dropin_fail_invalid); | 504 | STAT(tlb_dropin_fail_invalid); |
437 | gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | 505 | gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); |
438 | return -EFAULT; | 506 | return -EFAULT; |
439 | 507 | ||
440 | failactive: | 508 | failactive: |
441 | /* Range invalidate active. Switch to UPM iff atomic */ | 509 | /* Range invalidate active. Switch to UPM iff atomic */ |
442 | if (!cb) | 510 | if (!cbk) |
443 | tfh_user_polling_mode(tfh); | 511 | tfh_user_polling_mode(tfh); |
444 | else | 512 | else |
445 | gru_flush_cache(tfh); | 513 | gru_flush_cache(tfh); |
514 | gru_flush_cache_cbe(cbe); | ||
446 | STAT(tlb_dropin_fail_range_active); | 515 | STAT(tlb_dropin_fail_range_active); |
447 | gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n", | 516 | gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n", |
448 | tfh, vaddr); | 517 | tfh, vaddr); |
@@ -455,31 +524,41 @@ failactive: | |||
455 | * Note that this is the interrupt handler that is registered with linux | 524 | * Note that this is the interrupt handler that is registered with linux |
456 | * interrupt handlers. | 525 | * interrupt handlers. |
457 | */ | 526 | */ |
458 | irqreturn_t gru_intr(int irq, void *dev_id) | 527 | static irqreturn_t gru_intr(int chiplet, int blade) |
459 | { | 528 | { |
460 | struct gru_state *gru; | 529 | struct gru_state *gru; |
461 | struct gru_tlb_fault_map imap, dmap; | 530 | struct gru_tlb_fault_map imap, dmap; |
462 | struct gru_thread_state *gts; | 531 | struct gru_thread_state *gts; |
463 | struct gru_tlb_fault_handle *tfh = NULL; | 532 | struct gru_tlb_fault_handle *tfh = NULL; |
533 | struct completion *cmp; | ||
464 | int cbrnum, ctxnum; | 534 | int cbrnum, ctxnum; |
465 | 535 | ||
466 | STAT(intr); | 536 | STAT(intr); |
467 | 537 | ||
468 | gru = irq_to_gru(irq); | 538 | gru = &gru_base[blade]->bs_grus[chiplet]; |
469 | if (!gru) { | 539 | if (!gru) { |
470 | dev_err(grudev, "GRU: invalid interrupt: cpu %d, irq %d\n", | 540 | dev_err(grudev, "GRU: invalid interrupt: cpu %d, chiplet %d\n", |
471 | raw_smp_processor_id(), irq); | 541 | raw_smp_processor_id(), chiplet); |
472 | return IRQ_NONE; | 542 | return IRQ_NONE; |
473 | } | 543 | } |
474 | get_clear_fault_map(gru, &imap, &dmap); | 544 | get_clear_fault_map(gru, &imap, &dmap); |
545 | gru_dbg(grudev, | ||
546 | "cpu %d, chiplet %d, gid %d, imap %016lx %016lx, dmap %016lx %016lx\n", | ||
547 | smp_processor_id(), chiplet, gru->gs_gid, | ||
548 | imap.fault_bits[0], imap.fault_bits[1], | ||
549 | dmap.fault_bits[0], dmap.fault_bits[1]); | ||
475 | 550 | ||
476 | for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { | 551 | for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { |
477 | complete(gru->gs_blade->bs_async_wq); | 552 | STAT(intr_cbr); |
553 | cmp = gru->gs_blade->bs_async_wq; | ||
554 | if (cmp) | ||
555 | complete(cmp); | ||
478 | gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", | 556 | gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", |
479 | gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done); | 557 | gru->gs_gid, cbrnum, cmp ? cmp->done : -1); |
480 | } | 558 | } |
481 | 559 | ||
482 | for_each_cbr_in_tfm(cbrnum, imap.fault_bits) { | 560 | for_each_cbr_in_tfm(cbrnum, imap.fault_bits) { |
561 | STAT(intr_tfh); | ||
483 | tfh = get_tfh_by_index(gru, cbrnum); | 562 | tfh = get_tfh_by_index(gru, cbrnum); |
484 | prefetchw(tfh); /* Helps on hdw, required for emulator */ | 563 | prefetchw(tfh); /* Helps on hdw, required for emulator */ |
485 | 564 | ||
@@ -492,14 +571,20 @@ irqreturn_t gru_intr(int irq, void *dev_id) | |||
492 | ctxnum = tfh->ctxnum; | 571 | ctxnum = tfh->ctxnum; |
493 | gts = gru->gs_gts[ctxnum]; | 572 | gts = gru->gs_gts[ctxnum]; |
494 | 573 | ||
574 | /* Spurious interrupts can cause this. Ignore. */ | ||
575 | if (!gts) { | ||
576 | STAT(intr_spurious); | ||
577 | continue; | ||
578 | } | ||
579 | |||
495 | /* | 580 | /* |
496 | * This is running in interrupt context. Trylock the mmap_sem. | 581 | * This is running in interrupt context. Trylock the mmap_sem. |
497 | * If it fails, retry the fault in user context. | 582 | * If it fails, retry the fault in user context. |
498 | */ | 583 | */ |
584 | gts->ustats.fmm_tlbmiss++; | ||
499 | if (!gts->ts_force_cch_reload && | 585 | if (!gts->ts_force_cch_reload && |
500 | down_read_trylock(>s->ts_mm->mmap_sem)) { | 586 | down_read_trylock(>s->ts_mm->mmap_sem)) { |
501 | gts->ustats.fmm_tlbdropin++; | 587 | gru_try_dropin(gru, gts, tfh, NULL); |
502 | gru_try_dropin(gts, tfh, NULL); | ||
503 | up_read(>s->ts_mm->mmap_sem); | 588 | up_read(>s->ts_mm->mmap_sem); |
504 | } else { | 589 | } else { |
505 | tfh_user_polling_mode(tfh); | 590 | tfh_user_polling_mode(tfh); |
@@ -509,20 +594,43 @@ irqreturn_t gru_intr(int irq, void *dev_id) | |||
509 | return IRQ_HANDLED; | 594 | return IRQ_HANDLED; |
510 | } | 595 | } |
511 | 596 | ||
597 | irqreturn_t gru0_intr(int irq, void *dev_id) | ||
598 | { | ||
599 | return gru_intr(0, uv_numa_blade_id()); | ||
600 | } | ||
601 | |||
602 | irqreturn_t gru1_intr(int irq, void *dev_id) | ||
603 | { | ||
604 | return gru_intr(1, uv_numa_blade_id()); | ||
605 | } | ||
606 | |||
607 | irqreturn_t gru_intr_mblade(int irq, void *dev_id) | ||
608 | { | ||
609 | int blade; | ||
610 | |||
611 | for_each_possible_blade(blade) { | ||
612 | if (uv_blade_nr_possible_cpus(blade)) | ||
613 | continue; | ||
614 | gru_intr(0, blade); | ||
615 | gru_intr(1, blade); | ||
616 | } | ||
617 | return IRQ_HANDLED; | ||
618 | } | ||
619 | |||
512 | 620 | ||
513 | static int gru_user_dropin(struct gru_thread_state *gts, | 621 | static int gru_user_dropin(struct gru_thread_state *gts, |
514 | struct gru_tlb_fault_handle *tfh, | 622 | struct gru_tlb_fault_handle *tfh, |
515 | unsigned long __user *cb) | 623 | void *cb) |
516 | { | 624 | { |
517 | struct gru_mm_struct *gms = gts->ts_gms; | 625 | struct gru_mm_struct *gms = gts->ts_gms; |
518 | int ret; | 626 | int ret; |
519 | 627 | ||
520 | gts->ustats.upm_tlbdropin++; | 628 | gts->ustats.upm_tlbmiss++; |
521 | while (1) { | 629 | while (1) { |
522 | wait_event(gms->ms_wait_queue, | 630 | wait_event(gms->ms_wait_queue, |
523 | atomic_read(&gms->ms_range_active) == 0); | 631 | atomic_read(&gms->ms_range_active) == 0); |
524 | prefetchw(tfh); /* Helps on hdw, required for emulator */ | 632 | prefetchw(tfh); /* Helps on hdw, required for emulator */ |
525 | ret = gru_try_dropin(gts, tfh, cb); | 633 | ret = gru_try_dropin(gts->ts_gru, gts, tfh, cb); |
526 | if (ret <= 0) | 634 | if (ret <= 0) |
527 | return ret; | 635 | return ret; |
528 | STAT(call_os_wait_queue); | 636 | STAT(call_os_wait_queue); |
@@ -538,52 +646,41 @@ int gru_handle_user_call_os(unsigned long cb) | |||
538 | { | 646 | { |
539 | struct gru_tlb_fault_handle *tfh; | 647 | struct gru_tlb_fault_handle *tfh; |
540 | struct gru_thread_state *gts; | 648 | struct gru_thread_state *gts; |
541 | unsigned long __user *cbp; | 649 | void *cbk; |
542 | int ucbnum, cbrnum, ret = -EINVAL; | 650 | int ucbnum, cbrnum, ret = -EINVAL; |
543 | 651 | ||
544 | STAT(call_os); | 652 | STAT(call_os); |
545 | gru_dbg(grudev, "address 0x%lx\n", cb); | ||
546 | 653 | ||
547 | /* sanity check the cb pointer */ | 654 | /* sanity check the cb pointer */ |
548 | ucbnum = get_cb_number((void *)cb); | 655 | ucbnum = get_cb_number((void *)cb); |
549 | if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) | 656 | if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) |
550 | return -EINVAL; | 657 | return -EINVAL; |
551 | cbp = (unsigned long *)cb; | ||
552 | 658 | ||
553 | gts = gru_find_lock_gts(cb); | 659 | gts = gru_find_lock_gts(cb); |
554 | if (!gts) | 660 | if (!gts) |
555 | return -EINVAL; | 661 | return -EINVAL; |
662 | gru_dbg(grudev, "address 0x%lx, gid %d, gts 0x%p\n", cb, gts->ts_gru ? gts->ts_gru->gs_gid : -1, gts); | ||
556 | 663 | ||
557 | if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) | 664 | if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) |
558 | goto exit; | 665 | goto exit; |
559 | 666 | ||
560 | /* | 667 | gru_check_context_placement(gts); |
561 | * If force_unload is set, the UPM TLB fault is phony. The task | ||
562 | * has migrated to another node and the GSEG must be moved. Just | ||
563 | * unload the context. The task will page fault and assign a new | ||
564 | * context. | ||
565 | */ | ||
566 | if (gts->ts_tgid_owner == current->tgid && gts->ts_blade >= 0 && | ||
567 | gts->ts_blade != uv_numa_blade_id()) { | ||
568 | STAT(call_os_offnode_reference); | ||
569 | gts->ts_force_unload = 1; | ||
570 | } | ||
571 | 668 | ||
572 | /* | 669 | /* |
573 | * CCH may contain stale data if ts_force_cch_reload is set. | 670 | * CCH may contain stale data if ts_force_cch_reload is set. |
574 | */ | 671 | */ |
575 | if (gts->ts_gru && gts->ts_force_cch_reload) { | 672 | if (gts->ts_gru && gts->ts_force_cch_reload) { |
576 | gts->ts_force_cch_reload = 0; | 673 | gts->ts_force_cch_reload = 0; |
577 | gru_update_cch(gts, 0); | 674 | gru_update_cch(gts); |
578 | } | 675 | } |
579 | 676 | ||
580 | ret = -EAGAIN; | 677 | ret = -EAGAIN; |
581 | cbrnum = thread_cbr_number(gts, ucbnum); | 678 | cbrnum = thread_cbr_number(gts, ucbnum); |
582 | if (gts->ts_force_unload) { | 679 | if (gts->ts_gru) { |
583 | gru_unload_context(gts, 1); | ||
584 | } else if (gts->ts_gru) { | ||
585 | tfh = get_tfh_by_index(gts->ts_gru, cbrnum); | 680 | tfh = get_tfh_by_index(gts->ts_gru, cbrnum); |
586 | ret = gru_user_dropin(gts, tfh, cbp); | 681 | cbk = get_gseg_base_address_cb(gts->ts_gru->gs_gru_base_vaddr, |
682 | gts->ts_ctxnum, ucbnum); | ||
683 | ret = gru_user_dropin(gts, tfh, cbk); | ||
587 | } | 684 | } |
588 | exit: | 685 | exit: |
589 | gru_unlock_gts(gts); | 686 | gru_unlock_gts(gts); |
@@ -605,11 +702,11 @@ int gru_get_exception_detail(unsigned long arg) | |||
605 | if (copy_from_user(&excdet, (void __user *)arg, sizeof(excdet))) | 702 | if (copy_from_user(&excdet, (void __user *)arg, sizeof(excdet))) |
606 | return -EFAULT; | 703 | return -EFAULT; |
607 | 704 | ||
608 | gru_dbg(grudev, "address 0x%lx\n", excdet.cb); | ||
609 | gts = gru_find_lock_gts(excdet.cb); | 705 | gts = gru_find_lock_gts(excdet.cb); |
610 | if (!gts) | 706 | if (!gts) |
611 | return -EINVAL; | 707 | return -EINVAL; |
612 | 708 | ||
709 | gru_dbg(grudev, "address 0x%lx, gid %d, gts 0x%p\n", excdet.cb, gts->ts_gru ? gts->ts_gru->gs_gid : -1, gts); | ||
613 | ucbnum = get_cb_number((void *)excdet.cb); | 710 | ucbnum = get_cb_number((void *)excdet.cb); |
614 | if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { | 711 | if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { |
615 | ret = -EINVAL; | 712 | ret = -EINVAL; |
@@ -617,6 +714,7 @@ int gru_get_exception_detail(unsigned long arg) | |||
617 | cbrnum = thread_cbr_number(gts, ucbnum); | 714 | cbrnum = thread_cbr_number(gts, ucbnum); |
618 | cbe = get_cbe_by_index(gts->ts_gru, cbrnum); | 715 | cbe = get_cbe_by_index(gts->ts_gru, cbrnum); |
619 | gru_flush_cache(cbe); /* CBE not coherent */ | 716 | gru_flush_cache(cbe); /* CBE not coherent */ |
717 | sync_core(); /* make sure we are have current data */ | ||
620 | excdet.opc = cbe->opccpy; | 718 | excdet.opc = cbe->opccpy; |
621 | excdet.exopc = cbe->exopccpy; | 719 | excdet.exopc = cbe->exopccpy; |
622 | excdet.ecause = cbe->ecause; | 720 | excdet.ecause = cbe->ecause; |
@@ -624,7 +722,7 @@ int gru_get_exception_detail(unsigned long arg) | |||
624 | excdet.exceptdet1 = cbe->idef3upd; | 722 | excdet.exceptdet1 = cbe->idef3upd; |
625 | excdet.cbrstate = cbe->cbrstate; | 723 | excdet.cbrstate = cbe->cbrstate; |
626 | excdet.cbrexecstatus = cbe->cbrexecstatus; | 724 | excdet.cbrexecstatus = cbe->cbrexecstatus; |
627 | gru_flush_cache(cbe); | 725 | gru_flush_cache_cbe(cbe); |
628 | ret = 0; | 726 | ret = 0; |
629 | } else { | 727 | } else { |
630 | ret = -EAGAIN; | 728 | ret = -EAGAIN; |
@@ -733,6 +831,11 @@ long gru_get_gseg_statistics(unsigned long arg) | |||
733 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) | 831 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) |
734 | return -EFAULT; | 832 | return -EFAULT; |
735 | 833 | ||
834 | /* | ||
835 | * The library creates arrays of contexts for threaded programs. | ||
836 | * If no gts exists in the array, the context has never been used & all | ||
837 | * statistics are implicitly 0. | ||
838 | */ | ||
736 | gts = gru_find_lock_gts(req.gseg); | 839 | gts = gru_find_lock_gts(req.gseg); |
737 | if (gts) { | 840 | if (gts) { |
738 | memcpy(&req.stats, >s->ustats, sizeof(gts->ustats)); | 841 | memcpy(&req.stats, >s->ustats, sizeof(gts->ustats)); |
@@ -762,11 +865,25 @@ int gru_set_context_option(unsigned long arg) | |||
762 | return -EFAULT; | 865 | return -EFAULT; |
763 | gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); | 866 | gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); |
764 | 867 | ||
765 | gts = gru_alloc_locked_gts(req.gseg); | 868 | gts = gru_find_lock_gts(req.gseg); |
766 | if (!gts) | 869 | if (!gts) { |
767 | return -EINVAL; | 870 | gts = gru_alloc_locked_gts(req.gseg); |
871 | if (IS_ERR(gts)) | ||
872 | return PTR_ERR(gts); | ||
873 | } | ||
768 | 874 | ||
769 | switch (req.op) { | 875 | switch (req.op) { |
876 | case sco_blade_chiplet: | ||
877 | /* Select blade/chiplet for GRU context */ | ||
878 | if (req.val1 < -1 || req.val1 >= GRU_MAX_BLADES || !gru_base[req.val1] || | ||
879 | req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB) { | ||
880 | ret = -EINVAL; | ||
881 | } else { | ||
882 | gts->ts_user_blade_id = req.val1; | ||
883 | gts->ts_user_chiplet_id = req.val0; | ||
884 | gru_check_context_placement(gts); | ||
885 | } | ||
886 | break; | ||
770 | case sco_gseg_owner: | 887 | case sco_gseg_owner: |
771 | /* Register the current task as the GSEG owner */ | 888 | /* Register the current task as the GSEG owner */ |
772 | gts->ts_tgid_owner = current->tgid; | 889 | gts->ts_tgid_owner = current->tgid; |
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index ce5eda985ab0..cb3b4d228475 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c | |||
@@ -35,6 +35,9 @@ | |||
35 | #include <linux/interrupt.h> | 35 | #include <linux/interrupt.h> |
36 | #include <linux/proc_fs.h> | 36 | #include <linux/proc_fs.h> |
37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
38 | #ifdef CONFIG_X86_64 | ||
39 | #include <asm/uv/uv_irq.h> | ||
40 | #endif | ||
38 | #include <asm/uv/uv.h> | 41 | #include <asm/uv/uv.h> |
39 | #include "gru.h" | 42 | #include "gru.h" |
40 | #include "grulib.h" | 43 | #include "grulib.h" |
@@ -130,7 +133,6 @@ static int gru_create_new_context(unsigned long arg) | |||
130 | struct gru_vma_data *vdata; | 133 | struct gru_vma_data *vdata; |
131 | int ret = -EINVAL; | 134 | int ret = -EINVAL; |
132 | 135 | ||
133 | |||
134 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) | 136 | if (copy_from_user(&req, (void __user *)arg, sizeof(req))) |
135 | return -EFAULT; | 137 | return -EFAULT; |
136 | 138 | ||
@@ -150,6 +152,7 @@ static int gru_create_new_context(unsigned long arg) | |||
150 | vdata->vd_dsr_au_count = | 152 | vdata->vd_dsr_au_count = |
151 | GRU_DS_BYTES_TO_AU(req.data_segment_bytes); | 153 | GRU_DS_BYTES_TO_AU(req.data_segment_bytes); |
152 | vdata->vd_cbr_au_count = GRU_CB_COUNT_TO_AU(req.control_blocks); | 154 | vdata->vd_cbr_au_count = GRU_CB_COUNT_TO_AU(req.control_blocks); |
155 | vdata->vd_tlb_preload_count = req.tlb_preload_count; | ||
153 | ret = 0; | 156 | ret = 0; |
154 | } | 157 | } |
155 | up_write(¤t->mm->mmap_sem); | 158 | up_write(¤t->mm->mmap_sem); |
@@ -190,7 +193,7 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, | |||
190 | { | 193 | { |
191 | int err = -EBADRQC; | 194 | int err = -EBADRQC; |
192 | 195 | ||
193 | gru_dbg(grudev, "file %p\n", file); | 196 | gru_dbg(grudev, "file %p, req 0x%x, 0x%lx\n", file, req, arg); |
194 | 197 | ||
195 | switch (req) { | 198 | switch (req) { |
196 | case GRU_CREATE_CONTEXT: | 199 | case GRU_CREATE_CONTEXT: |
@@ -232,23 +235,24 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, | |||
232 | * system. | 235 | * system. |
233 | */ | 236 | */ |
234 | static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, | 237 | static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, |
235 | void *vaddr, int nid, int bid, int grunum) | 238 | void *vaddr, int blade_id, int chiplet_id) |
236 | { | 239 | { |
237 | spin_lock_init(&gru->gs_lock); | 240 | spin_lock_init(&gru->gs_lock); |
238 | spin_lock_init(&gru->gs_asid_lock); | 241 | spin_lock_init(&gru->gs_asid_lock); |
239 | gru->gs_gru_base_paddr = paddr; | 242 | gru->gs_gru_base_paddr = paddr; |
240 | gru->gs_gru_base_vaddr = vaddr; | 243 | gru->gs_gru_base_vaddr = vaddr; |
241 | gru->gs_gid = bid * GRU_CHIPLETS_PER_BLADE + grunum; | 244 | gru->gs_gid = blade_id * GRU_CHIPLETS_PER_BLADE + chiplet_id; |
242 | gru->gs_blade = gru_base[bid]; | 245 | gru->gs_blade = gru_base[blade_id]; |
243 | gru->gs_blade_id = bid; | 246 | gru->gs_blade_id = blade_id; |
247 | gru->gs_chiplet_id = chiplet_id; | ||
244 | gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1; | 248 | gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1; |
245 | gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1; | 249 | gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1; |
246 | gru->gs_asid_limit = MAX_ASID; | 250 | gru->gs_asid_limit = MAX_ASID; |
247 | gru_tgh_flush_init(gru); | 251 | gru_tgh_flush_init(gru); |
248 | if (gru->gs_gid >= gru_max_gids) | 252 | if (gru->gs_gid >= gru_max_gids) |
249 | gru_max_gids = gru->gs_gid + 1; | 253 | gru_max_gids = gru->gs_gid + 1; |
250 | gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n", | 254 | gru_dbg(grudev, "bid %d, gid %d, vaddr %p (0x%lx)\n", |
251 | bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr, | 255 | blade_id, gru->gs_gid, gru->gs_gru_base_vaddr, |
252 | gru->gs_gru_base_paddr); | 256 | gru->gs_gru_base_paddr); |
253 | } | 257 | } |
254 | 258 | ||
@@ -264,12 +268,10 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) | |||
264 | 268 | ||
265 | max_user_cbrs = GRU_NUM_CB; | 269 | max_user_cbrs = GRU_NUM_CB; |
266 | max_user_dsr_bytes = GRU_NUM_DSR_BYTES; | 270 | max_user_dsr_bytes = GRU_NUM_DSR_BYTES; |
267 | for_each_online_node(nid) { | 271 | for_each_possible_blade(bid) { |
268 | bid = uv_node_to_blade_id(nid); | 272 | pnode = uv_blade_to_pnode(bid); |
269 | pnode = uv_node_to_pnode(nid); | 273 | nid = uv_blade_to_memory_nid(bid);/* -1 if no memory on blade */ |
270 | if (bid < 0 || gru_base[bid]) | 274 | page = alloc_pages_node(nid, GFP_KERNEL, order); |
271 | continue; | ||
272 | page = alloc_pages_exact_node(nid, GFP_KERNEL, order); | ||
273 | if (!page) | 275 | if (!page) |
274 | goto fail; | 276 | goto fail; |
275 | gru_base[bid] = page_address(page); | 277 | gru_base[bid] = page_address(page); |
@@ -285,7 +287,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) | |||
285 | chip++, gru++) { | 287 | chip++, gru++) { |
286 | paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip); | 288 | paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip); |
287 | vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip); | 289 | vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip); |
288 | gru_init_chiplet(gru, paddr, vaddr, nid, bid, chip); | 290 | gru_init_chiplet(gru, paddr, vaddr, bid, chip); |
289 | n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; | 291 | n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; |
290 | cbrs = max(cbrs, n); | 292 | cbrs = max(cbrs, n); |
291 | n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; | 293 | n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; |
@@ -298,39 +300,215 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) | |||
298 | return 0; | 300 | return 0; |
299 | 301 | ||
300 | fail: | 302 | fail: |
301 | for (nid--; nid >= 0; nid--) | 303 | for (bid--; bid >= 0; bid--) |
302 | free_pages((unsigned long)gru_base[nid], order); | 304 | free_pages((unsigned long)gru_base[bid], order); |
303 | return -ENOMEM; | 305 | return -ENOMEM; |
304 | } | 306 | } |
305 | 307 | ||
306 | #ifdef CONFIG_IA64 | 308 | static void gru_free_tables(void) |
309 | { | ||
310 | int bid; | ||
311 | int order = get_order(sizeof(struct gru_state) * | ||
312 | GRU_CHIPLETS_PER_BLADE); | ||
307 | 313 | ||
308 | static int get_base_irq(void) | 314 | for (bid = 0; bid < GRU_MAX_BLADES; bid++) |
315 | free_pages((unsigned long)gru_base[bid], order); | ||
316 | } | ||
317 | |||
318 | static unsigned long gru_chiplet_cpu_to_mmr(int chiplet, int cpu, int *corep) | ||
309 | { | 319 | { |
310 | return IRQ_GRU; | 320 | unsigned long mmr = 0; |
321 | int core; | ||
322 | |||
323 | /* | ||
324 | * We target the cores of a blade and not the hyperthreads themselves. | ||
325 | * There is a max of 8 cores per socket and 2 sockets per blade, | ||
326 | * making for a max total of 16 cores (i.e., 16 CPUs without | ||
327 | * hyperthreading and 32 CPUs with hyperthreading). | ||
328 | */ | ||
329 | core = uv_cpu_core_number(cpu) + UV_MAX_INT_CORES * uv_cpu_socket_number(cpu); | ||
330 | if (core >= GRU_NUM_TFM || uv_cpu_ht_number(cpu)) | ||
331 | return 0; | ||
332 | |||
333 | if (chiplet == 0) { | ||
334 | mmr = UVH_GR0_TLB_INT0_CONFIG + | ||
335 | core * (UVH_GR0_TLB_INT1_CONFIG - UVH_GR0_TLB_INT0_CONFIG); | ||
336 | } else if (chiplet == 1) { | ||
337 | mmr = UVH_GR1_TLB_INT0_CONFIG + | ||
338 | core * (UVH_GR1_TLB_INT1_CONFIG - UVH_GR1_TLB_INT0_CONFIG); | ||
339 | } else { | ||
340 | BUG(); | ||
341 | } | ||
342 | |||
343 | *corep = core; | ||
344 | return mmr; | ||
311 | } | 345 | } |
312 | 346 | ||
313 | #elif defined CONFIG_X86_64 | 347 | #ifdef CONFIG_IA64 |
314 | 348 | ||
315 | static void noop(unsigned int irq) | 349 | static int gru_irq_count[GRU_CHIPLETS_PER_BLADE]; |
350 | |||
351 | static void gru_noop(unsigned int irq) | ||
316 | { | 352 | { |
317 | } | 353 | } |
318 | 354 | ||
319 | static struct irq_chip gru_chip = { | 355 | static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = { |
320 | .name = "gru", | 356 | [0 ... GRU_CHIPLETS_PER_BLADE - 1] { |
321 | .mask = noop, | 357 | .mask = gru_noop, |
322 | .unmask = noop, | 358 | .unmask = gru_noop, |
323 | .ack = noop, | 359 | .ack = gru_noop |
360 | } | ||
324 | }; | 361 | }; |
325 | 362 | ||
326 | static int get_base_irq(void) | 363 | static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name, |
364 | irq_handler_t irq_handler, int cpu, int blade) | ||
365 | { | ||
366 | unsigned long mmr; | ||
367 | int irq = IRQ_GRU + chiplet; | ||
368 | int ret, core; | ||
369 | |||
370 | mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core); | ||
371 | if (mmr == 0) | ||
372 | return 0; | ||
373 | |||
374 | if (gru_irq_count[chiplet] == 0) { | ||
375 | gru_chip[chiplet].name = irq_name; | ||
376 | ret = set_irq_chip(irq, &gru_chip[chiplet]); | ||
377 | if (ret) { | ||
378 | printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", | ||
379 | GRU_DRIVER_ID_STR, -ret); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | ret = request_irq(irq, irq_handler, 0, irq_name, NULL); | ||
384 | if (ret) { | ||
385 | printk(KERN_ERR "%s: request_irq failed, errno=%d\n", | ||
386 | GRU_DRIVER_ID_STR, -ret); | ||
387 | return ret; | ||
388 | } | ||
389 | } | ||
390 | gru_irq_count[chiplet]++; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static void gru_chiplet_teardown_tlb_irq(int chiplet, int cpu, int blade) | ||
396 | { | ||
397 | unsigned long mmr; | ||
398 | int core, irq = IRQ_GRU + chiplet; | ||
399 | |||
400 | if (gru_irq_count[chiplet] == 0) | ||
401 | return; | ||
402 | |||
403 | mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core); | ||
404 | if (mmr == 0) | ||
405 | return; | ||
406 | |||
407 | if (--gru_irq_count[chiplet] == 0) | ||
408 | free_irq(irq, NULL); | ||
409 | } | ||
410 | |||
411 | #elif defined CONFIG_X86_64 | ||
412 | |||
413 | static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name, | ||
414 | irq_handler_t irq_handler, int cpu, int blade) | ||
415 | { | ||
416 | unsigned long mmr; | ||
417 | int irq, core; | ||
418 | int ret; | ||
419 | |||
420 | mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core); | ||
421 | if (mmr == 0) | ||
422 | return 0; | ||
423 | |||
424 | irq = uv_setup_irq(irq_name, cpu, blade, mmr, UV_AFFINITY_CPU); | ||
425 | if (irq < 0) { | ||
426 | printk(KERN_ERR "%s: uv_setup_irq failed, errno=%d\n", | ||
427 | GRU_DRIVER_ID_STR, -irq); | ||
428 | return irq; | ||
429 | } | ||
430 | |||
431 | ret = request_irq(irq, irq_handler, 0, irq_name, NULL); | ||
432 | if (ret) { | ||
433 | uv_teardown_irq(irq); | ||
434 | printk(KERN_ERR "%s: request_irq failed, errno=%d\n", | ||
435 | GRU_DRIVER_ID_STR, -ret); | ||
436 | return ret; | ||
437 | } | ||
438 | gru_base[blade]->bs_grus[chiplet].gs_irq[core] = irq; | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static void gru_chiplet_teardown_tlb_irq(int chiplet, int cpu, int blade) | ||
327 | { | 443 | { |
328 | set_irq_chip(IRQ_GRU, &gru_chip); | 444 | int irq, core; |
329 | set_irq_chip(IRQ_GRU + 1, &gru_chip); | 445 | unsigned long mmr; |
330 | return IRQ_GRU; | 446 | |
447 | mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core); | ||
448 | if (mmr) { | ||
449 | irq = gru_base[blade]->bs_grus[chiplet].gs_irq[core]; | ||
450 | if (irq) { | ||
451 | free_irq(irq, NULL); | ||
452 | uv_teardown_irq(irq); | ||
453 | } | ||
454 | } | ||
331 | } | 455 | } |
456 | |||
332 | #endif | 457 | #endif |
333 | 458 | ||
459 | static void gru_teardown_tlb_irqs(void) | ||
460 | { | ||
461 | int blade; | ||
462 | int cpu; | ||
463 | |||
464 | for_each_online_cpu(cpu) { | ||
465 | blade = uv_cpu_to_blade_id(cpu); | ||
466 | gru_chiplet_teardown_tlb_irq(0, cpu, blade); | ||
467 | gru_chiplet_teardown_tlb_irq(1, cpu, blade); | ||
468 | } | ||
469 | for_each_possible_blade(blade) { | ||
470 | if (uv_blade_nr_possible_cpus(blade)) | ||
471 | continue; | ||
472 | gru_chiplet_teardown_tlb_irq(0, 0, blade); | ||
473 | gru_chiplet_teardown_tlb_irq(1, 0, blade); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | static int gru_setup_tlb_irqs(void) | ||
478 | { | ||
479 | int blade; | ||
480 | int cpu; | ||
481 | int ret; | ||
482 | |||
483 | for_each_online_cpu(cpu) { | ||
484 | blade = uv_cpu_to_blade_id(cpu); | ||
485 | ret = gru_chiplet_setup_tlb_irq(0, "GRU0_TLB", gru0_intr, cpu, blade); | ||
486 | if (ret != 0) | ||
487 | goto exit1; | ||
488 | |||
489 | ret = gru_chiplet_setup_tlb_irq(1, "GRU1_TLB", gru1_intr, cpu, blade); | ||
490 | if (ret != 0) | ||
491 | goto exit1; | ||
492 | } | ||
493 | for_each_possible_blade(blade) { | ||
494 | if (uv_blade_nr_possible_cpus(blade)) | ||
495 | continue; | ||
496 | ret = gru_chiplet_setup_tlb_irq(0, "GRU0_TLB", gru_intr_mblade, 0, blade); | ||
497 | if (ret != 0) | ||
498 | goto exit1; | ||
499 | |||
500 | ret = gru_chiplet_setup_tlb_irq(1, "GRU1_TLB", gru_intr_mblade, 0, blade); | ||
501 | if (ret != 0) | ||
502 | goto exit1; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | |||
507 | exit1: | ||
508 | gru_teardown_tlb_irqs(); | ||
509 | return ret; | ||
510 | } | ||
511 | |||
334 | /* | 512 | /* |
335 | * gru_init | 513 | * gru_init |
336 | * | 514 | * |
@@ -338,8 +516,7 @@ static int get_base_irq(void) | |||
338 | */ | 516 | */ |
339 | static int __init gru_init(void) | 517 | static int __init gru_init(void) |
340 | { | 518 | { |
341 | int ret, irq, chip; | 519 | int ret; |
342 | char id[10]; | ||
343 | 520 | ||
344 | if (!is_uv_system()) | 521 | if (!is_uv_system()) |
345 | return 0; | 522 | return 0; |
@@ -354,41 +531,29 @@ static int __init gru_init(void) | |||
354 | gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE; | 531 | gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE; |
355 | printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n", | 532 | printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n", |
356 | gru_start_paddr, gru_end_paddr); | 533 | gru_start_paddr, gru_end_paddr); |
357 | irq = get_base_irq(); | ||
358 | for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) { | ||
359 | ret = request_irq(irq + chip, gru_intr, 0, id, NULL); | ||
360 | /* TODO: fix irq handling on x86. For now ignore failure because | ||
361 | * interrupts are not required & not yet fully supported */ | ||
362 | if (ret) { | ||
363 | printk(KERN_WARNING | ||
364 | "!!!WARNING: GRU ignoring request failure!!!\n"); | ||
365 | ret = 0; | ||
366 | } | ||
367 | if (ret) { | ||
368 | printk(KERN_ERR "%s: request_irq failed\n", | ||
369 | GRU_DRIVER_ID_STR); | ||
370 | goto exit1; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | ret = misc_register(&gru_miscdev); | 534 | ret = misc_register(&gru_miscdev); |
375 | if (ret) { | 535 | if (ret) { |
376 | printk(KERN_ERR "%s: misc_register failed\n", | 536 | printk(KERN_ERR "%s: misc_register failed\n", |
377 | GRU_DRIVER_ID_STR); | 537 | GRU_DRIVER_ID_STR); |
378 | goto exit1; | 538 | goto exit0; |
379 | } | 539 | } |
380 | 540 | ||
381 | ret = gru_proc_init(); | 541 | ret = gru_proc_init(); |
382 | if (ret) { | 542 | if (ret) { |
383 | printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR); | 543 | printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR); |
384 | goto exit2; | 544 | goto exit1; |
385 | } | 545 | } |
386 | 546 | ||
387 | ret = gru_init_tables(gru_start_paddr, gru_start_vaddr); | 547 | ret = gru_init_tables(gru_start_paddr, gru_start_vaddr); |
388 | if (ret) { | 548 | if (ret) { |
389 | printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR); | 549 | printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR); |
390 | goto exit3; | 550 | goto exit2; |
391 | } | 551 | } |
552 | |||
553 | ret = gru_setup_tlb_irqs(); | ||
554 | if (ret != 0) | ||
555 | goto exit3; | ||
556 | |||
392 | gru_kservices_init(); | 557 | gru_kservices_init(); |
393 | 558 | ||
394 | printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR, | 559 | printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR, |
@@ -396,31 +561,24 @@ static int __init gru_init(void) | |||
396 | return 0; | 561 | return 0; |
397 | 562 | ||
398 | exit3: | 563 | exit3: |
399 | gru_proc_exit(); | 564 | gru_free_tables(); |
400 | exit2: | 565 | exit2: |
401 | misc_deregister(&gru_miscdev); | 566 | gru_proc_exit(); |
402 | exit1: | 567 | exit1: |
403 | for (--chip; chip >= 0; chip--) | 568 | misc_deregister(&gru_miscdev); |
404 | free_irq(irq + chip, NULL); | 569 | exit0: |
405 | return ret; | 570 | return ret; |
406 | 571 | ||
407 | } | 572 | } |
408 | 573 | ||
409 | static void __exit gru_exit(void) | 574 | static void __exit gru_exit(void) |
410 | { | 575 | { |
411 | int i, bid; | ||
412 | int order = get_order(sizeof(struct gru_state) * | ||
413 | GRU_CHIPLETS_PER_BLADE); | ||
414 | |||
415 | if (!is_uv_system()) | 576 | if (!is_uv_system()) |
416 | return; | 577 | return; |
417 | 578 | ||
418 | for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) | 579 | gru_teardown_tlb_irqs(); |
419 | free_irq(IRQ_GRU + i, NULL); | ||
420 | gru_kservices_exit(); | 580 | gru_kservices_exit(); |
421 | for (bid = 0; bid < GRU_MAX_BLADES; bid++) | 581 | gru_free_tables(); |
422 | free_pages((unsigned long)gru_base[bid], order); | ||
423 | |||
424 | misc_deregister(&gru_miscdev); | 582 | misc_deregister(&gru_miscdev); |
425 | gru_proc_exit(); | 583 | gru_proc_exit(); |
426 | } | 584 | } |
diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c index 37e7cfc53b9c..2f30badc6ffd 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c | |||
@@ -27,9 +27,11 @@ | |||
27 | #ifdef CONFIG_IA64 | 27 | #ifdef CONFIG_IA64 |
28 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
29 | #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) | 29 | #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) |
30 | #define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq) | ||
30 | #else | 31 | #else |
31 | #include <asm/tsc.h> | 32 | #include <asm/tsc.h> |
32 | #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) | 33 | #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) |
34 | #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz) | ||
33 | #endif | 35 | #endif |
34 | 36 | ||
35 | /* Extract the status field from a kernel handle */ | 37 | /* Extract the status field from a kernel handle */ |
@@ -39,21 +41,39 @@ struct mcs_op_statistic mcs_op_statistics[mcsop_last]; | |||
39 | 41 | ||
40 | static void update_mcs_stats(enum mcs_op op, unsigned long clks) | 42 | static void update_mcs_stats(enum mcs_op op, unsigned long clks) |
41 | { | 43 | { |
44 | unsigned long nsec; | ||
45 | |||
46 | nsec = CLKS2NSEC(clks); | ||
42 | atomic_long_inc(&mcs_op_statistics[op].count); | 47 | atomic_long_inc(&mcs_op_statistics[op].count); |
43 | atomic_long_add(clks, &mcs_op_statistics[op].total); | 48 | atomic_long_add(nsec, &mcs_op_statistics[op].total); |
44 | if (mcs_op_statistics[op].max < clks) | 49 | if (mcs_op_statistics[op].max < nsec) |
45 | mcs_op_statistics[op].max = clks; | 50 | mcs_op_statistics[op].max = nsec; |
46 | } | 51 | } |
47 | 52 | ||
48 | static void start_instruction(void *h) | 53 | static void start_instruction(void *h) |
49 | { | 54 | { |
50 | unsigned long *w0 = h; | 55 | unsigned long *w0 = h; |
51 | 56 | ||
52 | wmb(); /* setting CMD bit must be last */ | 57 | wmb(); /* setting CMD/STATUS bits must be last */ |
53 | *w0 = *w0 | 1; | 58 | *w0 = *w0 | 0x20001; |
54 | gru_flush_cache(h); | 59 | gru_flush_cache(h); |
55 | } | 60 | } |
56 | 61 | ||
62 | static void report_instruction_timeout(void *h) | ||
63 | { | ||
64 | unsigned long goff = GSEGPOFF((unsigned long)h); | ||
65 | char *id = "???"; | ||
66 | |||
67 | if (TYPE_IS(CCH, goff)) | ||
68 | id = "CCH"; | ||
69 | else if (TYPE_IS(TGH, goff)) | ||
70 | id = "TGH"; | ||
71 | else if (TYPE_IS(TFH, goff)) | ||
72 | id = "TFH"; | ||
73 | |||
74 | panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id); | ||
75 | } | ||
76 | |||
57 | static int wait_instruction_complete(void *h, enum mcs_op opc) | 77 | static int wait_instruction_complete(void *h, enum mcs_op opc) |
58 | { | 78 | { |
59 | int status; | 79 | int status; |
@@ -64,9 +84,10 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) | |||
64 | status = GET_MSEG_HANDLE_STATUS(h); | 84 | status = GET_MSEG_HANDLE_STATUS(h); |
65 | if (status != CCHSTATUS_ACTIVE) | 85 | if (status != CCHSTATUS_ACTIVE) |
66 | break; | 86 | break; |
67 | if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) | 87 | if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) { |
68 | panic("GRU %p is malfunctioning: start %ld, end %ld\n", | 88 | report_instruction_timeout(h); |
69 | h, start_time, (unsigned long)get_cycles()); | 89 | start_time = get_cycles(); |
90 | } | ||
70 | } | 91 | } |
71 | if (gru_options & OPT_STATS) | 92 | if (gru_options & OPT_STATS) |
72 | update_mcs_stats(opc, get_cycles() - start_time); | 93 | update_mcs_stats(opc, get_cycles() - start_time); |
@@ -75,9 +96,18 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) | |||
75 | 96 | ||
76 | int cch_allocate(struct gru_context_configuration_handle *cch) | 97 | int cch_allocate(struct gru_context_configuration_handle *cch) |
77 | { | 98 | { |
99 | int ret; | ||
100 | |||
78 | cch->opc = CCHOP_ALLOCATE; | 101 | cch->opc = CCHOP_ALLOCATE; |
79 | start_instruction(cch); | 102 | start_instruction(cch); |
80 | return wait_instruction_complete(cch, cchop_allocate); | 103 | ret = wait_instruction_complete(cch, cchop_allocate); |
104 | |||
105 | /* | ||
106 | * Stop speculation into the GSEG being mapped by the previous ALLOCATE. | ||
107 | * The GSEG memory does not exist until the ALLOCATE completes. | ||
108 | */ | ||
109 | sync_core(); | ||
110 | return ret; | ||
81 | } | 111 | } |
82 | 112 | ||
83 | int cch_start(struct gru_context_configuration_handle *cch) | 113 | int cch_start(struct gru_context_configuration_handle *cch) |
@@ -96,9 +126,18 @@ int cch_interrupt(struct gru_context_configuration_handle *cch) | |||
96 | 126 | ||
97 | int cch_deallocate(struct gru_context_configuration_handle *cch) | 127 | int cch_deallocate(struct gru_context_configuration_handle *cch) |
98 | { | 128 | { |
129 | int ret; | ||
130 | |||
99 | cch->opc = CCHOP_DEALLOCATE; | 131 | cch->opc = CCHOP_DEALLOCATE; |
100 | start_instruction(cch); | 132 | start_instruction(cch); |
101 | return wait_instruction_complete(cch, cchop_deallocate); | 133 | ret = wait_instruction_complete(cch, cchop_deallocate); |
134 | |||
135 | /* | ||
136 | * Stop speculation into the GSEG being unmapped by the previous | ||
137 | * DEALLOCATE. | ||
138 | */ | ||
139 | sync_core(); | ||
140 | return ret; | ||
102 | } | 141 | } |
103 | 142 | ||
104 | int cch_interrupt_sync(struct gru_context_configuration_handle | 143 | int cch_interrupt_sync(struct gru_context_configuration_handle |
@@ -126,17 +165,20 @@ int tgh_invalidate(struct gru_tlb_global_handle *tgh, | |||
126 | return wait_instruction_complete(tgh, tghop_invalidate); | 165 | return wait_instruction_complete(tgh, tghop_invalidate); |
127 | } | 166 | } |
128 | 167 | ||
129 | void tfh_write_only(struct gru_tlb_fault_handle *tfh, | 168 | int tfh_write_only(struct gru_tlb_fault_handle *tfh, |
130 | unsigned long pfn, unsigned long vaddr, | 169 | unsigned long paddr, int gaa, |
131 | int asid, int dirty, int pagesize) | 170 | unsigned long vaddr, int asid, int dirty, |
171 | int pagesize) | ||
132 | { | 172 | { |
133 | tfh->fillasid = asid; | 173 | tfh->fillasid = asid; |
134 | tfh->fillvaddr = vaddr; | 174 | tfh->fillvaddr = vaddr; |
135 | tfh->pfn = pfn; | 175 | tfh->pfn = paddr >> GRU_PADDR_SHIFT; |
176 | tfh->gaa = gaa; | ||
136 | tfh->dirty = dirty; | 177 | tfh->dirty = dirty; |
137 | tfh->pagesize = pagesize; | 178 | tfh->pagesize = pagesize; |
138 | tfh->opc = TFHOP_WRITE_ONLY; | 179 | tfh->opc = TFHOP_WRITE_ONLY; |
139 | start_instruction(tfh); | 180 | start_instruction(tfh); |
181 | return wait_instruction_complete(tfh, tfhop_write_only); | ||
140 | } | 182 | } |
141 | 183 | ||
142 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, | 184 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, |
diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h index f44112242d00..3f998b924d8f 100644 --- a/drivers/misc/sgi-gru/gruhandles.h +++ b/drivers/misc/sgi-gru/gruhandles.h | |||
@@ -91,6 +91,12 @@ | |||
91 | /* Convert an arbitrary handle address to the beginning of the GRU segment */ | 91 | /* Convert an arbitrary handle address to the beginning of the GRU segment */ |
92 | #define GRUBASE(h) ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1))) | 92 | #define GRUBASE(h) ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1))) |
93 | 93 | ||
94 | /* Test a valid handle address to determine the type */ | ||
95 | #define TYPE_IS(hn, h) ((h) >= GRU_##hn##_BASE && (h) < \ | ||
96 | GRU_##hn##_BASE + GRU_NUM_##hn * GRU_HANDLE_STRIDE && \ | ||
97 | (((h) & (GRU_HANDLE_STRIDE - 1)) == 0)) | ||
98 | |||
99 | |||
94 | /* General addressing macros. */ | 100 | /* General addressing macros. */ |
95 | static inline void *get_gseg_base_address(void *base, int ctxnum) | 101 | static inline void *get_gseg_base_address(void *base, int ctxnum) |
96 | { | 102 | { |
@@ -158,6 +164,16 @@ static inline void *gru_chiplet_vaddr(void *vaddr, int pnode, int chiplet) | |||
158 | return vaddr + GRU_SIZE * (2 * pnode + chiplet); | 164 | return vaddr + GRU_SIZE * (2 * pnode + chiplet); |
159 | } | 165 | } |
160 | 166 | ||
167 | static inline struct gru_control_block_extended *gru_tfh_to_cbe( | ||
168 | struct gru_tlb_fault_handle *tfh) | ||
169 | { | ||
170 | unsigned long cbe; | ||
171 | |||
172 | cbe = (unsigned long)tfh - GRU_TFH_BASE + GRU_CBE_BASE; | ||
173 | return (struct gru_control_block_extended*)cbe; | ||
174 | } | ||
175 | |||
176 | |||
161 | 177 | ||
162 | 178 | ||
163 | /* | 179 | /* |
@@ -236,6 +252,17 @@ enum gru_tgh_state { | |||
236 | TGHSTATE_RESTART_CTX, | 252 | TGHSTATE_RESTART_CTX, |
237 | }; | 253 | }; |
238 | 254 | ||
255 | enum gru_tgh_cause { | ||
256 | TGHCAUSE_RR_ECC, | ||
257 | TGHCAUSE_TLB_ECC, | ||
258 | TGHCAUSE_LRU_ECC, | ||
259 | TGHCAUSE_PS_ECC, | ||
260 | TGHCAUSE_MUL_ERR, | ||
261 | TGHCAUSE_DATA_ERR, | ||
262 | TGHCAUSE_SW_FORCE | ||
263 | }; | ||
264 | |||
265 | |||
239 | /* | 266 | /* |
240 | * TFH - TLB Global Handle | 267 | * TFH - TLB Global Handle |
241 | * Used for TLB dropins into the GRU TLB. | 268 | * Used for TLB dropins into the GRU TLB. |
@@ -440,6 +467,12 @@ struct gru_control_block_extended { | |||
440 | unsigned int cbrexecstatus:8; | 467 | unsigned int cbrexecstatus:8; |
441 | }; | 468 | }; |
442 | 469 | ||
470 | /* CBE fields for active BCOPY instructions */ | ||
471 | #define cbe_baddr0 idef1upd | ||
472 | #define cbe_baddr1 idef3upd | ||
473 | #define cbe_src_cl idef6cpy | ||
474 | #define cbe_nelemcur idef5upd | ||
475 | |||
443 | enum gru_cbr_state { | 476 | enum gru_cbr_state { |
444 | CBRSTATE_INACTIVE, | 477 | CBRSTATE_INACTIVE, |
445 | CBRSTATE_IDLE, | 478 | CBRSTATE_IDLE, |
@@ -487,8 +520,8 @@ int cch_interrupt_sync(struct gru_context_configuration_handle *cch); | |||
487 | int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr, | 520 | int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr, |
488 | unsigned long vaddrmask, int asid, int pagesize, int global, int n, | 521 | unsigned long vaddrmask, int asid, int pagesize, int global, int n, |
489 | unsigned short ctxbitmap); | 522 | unsigned short ctxbitmap); |
490 | void tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn, | 523 | int tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long paddr, |
491 | unsigned long vaddr, int asid, int dirty, int pagesize); | 524 | int gaa, unsigned long vaddr, int asid, int dirty, int pagesize); |
492 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr, | 525 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr, |
493 | int gaa, unsigned long vaddr, int asid, int dirty, int pagesize); | 526 | int gaa, unsigned long vaddr, int asid, int dirty, int pagesize); |
494 | void tfh_restart(struct gru_tlb_fault_handle *tfh); | 527 | void tfh_restart(struct gru_tlb_fault_handle *tfh); |
diff --git a/drivers/misc/sgi-gru/grukdump.c b/drivers/misc/sgi-gru/grukdump.c index 55eabfa85585..9b2062d17327 100644 --- a/drivers/misc/sgi-gru/grukdump.c +++ b/drivers/misc/sgi-gru/grukdump.c | |||
@@ -44,7 +44,8 @@ static int gru_user_copy_handle(void __user **dp, void *s) | |||
44 | 44 | ||
45 | static int gru_dump_context_data(void *grubase, | 45 | static int gru_dump_context_data(void *grubase, |
46 | struct gru_context_configuration_handle *cch, | 46 | struct gru_context_configuration_handle *cch, |
47 | void __user *ubuf, int ctxnum, int dsrcnt) | 47 | void __user *ubuf, int ctxnum, int dsrcnt, |
48 | int flush_cbrs) | ||
48 | { | 49 | { |
49 | void *cb, *cbe, *tfh, *gseg; | 50 | void *cb, *cbe, *tfh, *gseg; |
50 | int i, scr; | 51 | int i, scr; |
@@ -55,6 +56,8 @@ static int gru_dump_context_data(void *grubase, | |||
55 | tfh = grubase + GRU_TFH_BASE; | 56 | tfh = grubase + GRU_TFH_BASE; |
56 | 57 | ||
57 | for_each_cbr_in_allocation_map(i, &cch->cbr_allocation_map, scr) { | 58 | for_each_cbr_in_allocation_map(i, &cch->cbr_allocation_map, scr) { |
59 | if (flush_cbrs) | ||
60 | gru_flush_cache(cb); | ||
58 | if (gru_user_copy_handle(&ubuf, cb)) | 61 | if (gru_user_copy_handle(&ubuf, cb)) |
59 | goto fail; | 62 | goto fail; |
60 | if (gru_user_copy_handle(&ubuf, tfh + i * GRU_HANDLE_STRIDE)) | 63 | if (gru_user_copy_handle(&ubuf, tfh + i * GRU_HANDLE_STRIDE)) |
@@ -115,7 +118,7 @@ fail: | |||
115 | 118 | ||
116 | static int gru_dump_context(struct gru_state *gru, int ctxnum, | 119 | static int gru_dump_context(struct gru_state *gru, int ctxnum, |
117 | void __user *ubuf, void __user *ubufend, char data_opt, | 120 | void __user *ubuf, void __user *ubufend, char data_opt, |
118 | char lock_cch) | 121 | char lock_cch, char flush_cbrs) |
119 | { | 122 | { |
120 | struct gru_dump_context_header hdr; | 123 | struct gru_dump_context_header hdr; |
121 | struct gru_dump_context_header __user *uhdr = ubuf; | 124 | struct gru_dump_context_header __user *uhdr = ubuf; |
@@ -159,8 +162,7 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum, | |||
159 | ret = -EFBIG; | 162 | ret = -EFBIG; |
160 | else | 163 | else |
161 | ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum, | 164 | ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum, |
162 | dsrcnt); | 165 | dsrcnt, flush_cbrs); |
163 | |||
164 | } | 166 | } |
165 | if (cch_locked) | 167 | if (cch_locked) |
166 | unlock_cch_handle(cch); | 168 | unlock_cch_handle(cch); |
@@ -215,7 +217,8 @@ int gru_dump_chiplet_request(unsigned long arg) | |||
215 | for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) { | 217 | for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) { |
216 | if (req.ctxnum == ctxnum || req.ctxnum < 0) { | 218 | if (req.ctxnum == ctxnum || req.ctxnum < 0) { |
217 | ret = gru_dump_context(gru, ctxnum, ubuf, ubufend, | 219 | ret = gru_dump_context(gru, ctxnum, ubuf, ubufend, |
218 | req.data_opt, req.lock_cch); | 220 | req.data_opt, req.lock_cch, |
221 | req.flush_cbrs); | ||
219 | if (ret < 0) | 222 | if (ret < 0) |
220 | goto fail; | 223 | goto fail; |
221 | ubuf += ret; | 224 | ubuf += ret; |
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 766e21e15574..34749ee88dfa 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/uaccess.h> | 32 | #include <linux/uaccess.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <asm/io_apic.h> | ||
34 | #include "gru.h" | 35 | #include "gru.h" |
35 | #include "grulib.h" | 36 | #include "grulib.h" |
36 | #include "grutables.h" | 37 | #include "grutables.h" |
@@ -97,9 +98,6 @@ | |||
97 | #define ASYNC_HAN_TO_BID(h) ((h) - 1) | 98 | #define ASYNC_HAN_TO_BID(h) ((h) - 1) |
98 | #define ASYNC_BID_TO_HAN(b) ((b) + 1) | 99 | #define ASYNC_BID_TO_HAN(b) ((b) + 1) |
99 | #define ASYNC_HAN_TO_BS(h) gru_base[ASYNC_HAN_TO_BID(h)] | 100 | #define ASYNC_HAN_TO_BS(h) gru_base[ASYNC_HAN_TO_BID(h)] |
100 | #define KCB_TO_GID(cb) ((cb - gru_start_vaddr) / \ | ||
101 | (GRU_SIZE * GRU_CHIPLETS_PER_BLADE)) | ||
102 | #define KCB_TO_BS(cb) gru_base[KCB_TO_GID(cb)] | ||
103 | 101 | ||
104 | #define GRU_NUM_KERNEL_CBR 1 | 102 | #define GRU_NUM_KERNEL_CBR 1 |
105 | #define GRU_NUM_KERNEL_DSR_BYTES 256 | 103 | #define GRU_NUM_KERNEL_DSR_BYTES 256 |
@@ -160,8 +158,10 @@ static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id) | |||
160 | up_read(&bs->bs_kgts_sema); | 158 | up_read(&bs->bs_kgts_sema); |
161 | down_write(&bs->bs_kgts_sema); | 159 | down_write(&bs->bs_kgts_sema); |
162 | 160 | ||
163 | if (!bs->bs_kgts) | 161 | if (!bs->bs_kgts) { |
164 | bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0); | 162 | bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0, 0); |
163 | bs->bs_kgts->ts_user_blade_id = blade_id; | ||
164 | } | ||
165 | kgts = bs->bs_kgts; | 165 | kgts = bs->bs_kgts; |
166 | 166 | ||
167 | if (!kgts->ts_gru) { | 167 | if (!kgts->ts_gru) { |
@@ -172,9 +172,9 @@ static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id) | |||
172 | kgts->ts_dsr_au_count = GRU_DS_BYTES_TO_AU( | 172 | kgts->ts_dsr_au_count = GRU_DS_BYTES_TO_AU( |
173 | GRU_NUM_KERNEL_DSR_BYTES * ncpus + | 173 | GRU_NUM_KERNEL_DSR_BYTES * ncpus + |
174 | bs->bs_async_dsr_bytes); | 174 | bs->bs_async_dsr_bytes); |
175 | while (!gru_assign_gru_context(kgts, blade_id)) { | 175 | while (!gru_assign_gru_context(kgts)) { |
176 | msleep(1); | 176 | msleep(1); |
177 | gru_steal_context(kgts, blade_id); | 177 | gru_steal_context(kgts); |
178 | } | 178 | } |
179 | gru_load_context(kgts); | 179 | gru_load_context(kgts); |
180 | gru = bs->bs_kgts->ts_gru; | 180 | gru = bs->bs_kgts->ts_gru; |
@@ -200,13 +200,15 @@ static int gru_free_kernel_contexts(void) | |||
200 | bs = gru_base[bid]; | 200 | bs = gru_base[bid]; |
201 | if (!bs) | 201 | if (!bs) |
202 | continue; | 202 | continue; |
203 | |||
204 | /* Ignore busy contexts. Don't want to block here. */ | ||
203 | if (down_write_trylock(&bs->bs_kgts_sema)) { | 205 | if (down_write_trylock(&bs->bs_kgts_sema)) { |
204 | kgts = bs->bs_kgts; | 206 | kgts = bs->bs_kgts; |
205 | if (kgts && kgts->ts_gru) | 207 | if (kgts && kgts->ts_gru) |
206 | gru_unload_context(kgts, 0); | 208 | gru_unload_context(kgts, 0); |
207 | kfree(kgts); | ||
208 | bs->bs_kgts = NULL; | 209 | bs->bs_kgts = NULL; |
209 | up_write(&bs->bs_kgts_sema); | 210 | up_write(&bs->bs_kgts_sema); |
211 | kfree(kgts); | ||
210 | } else { | 212 | } else { |
211 | ret++; | 213 | ret++; |
212 | } | 214 | } |
@@ -220,13 +222,21 @@ static int gru_free_kernel_contexts(void) | |||
220 | static struct gru_blade_state *gru_lock_kernel_context(int blade_id) | 222 | static struct gru_blade_state *gru_lock_kernel_context(int blade_id) |
221 | { | 223 | { |
222 | struct gru_blade_state *bs; | 224 | struct gru_blade_state *bs; |
225 | int bid; | ||
223 | 226 | ||
224 | STAT(lock_kernel_context); | 227 | STAT(lock_kernel_context); |
225 | bs = gru_base[blade_id]; | 228 | again: |
229 | bid = blade_id < 0 ? uv_numa_blade_id() : blade_id; | ||
230 | bs = gru_base[bid]; | ||
226 | 231 | ||
232 | /* Handle the case where migration occured while waiting for the sema */ | ||
227 | down_read(&bs->bs_kgts_sema); | 233 | down_read(&bs->bs_kgts_sema); |
234 | if (blade_id < 0 && bid != uv_numa_blade_id()) { | ||
235 | up_read(&bs->bs_kgts_sema); | ||
236 | goto again; | ||
237 | } | ||
228 | if (!bs->bs_kgts || !bs->bs_kgts->ts_gru) | 238 | if (!bs->bs_kgts || !bs->bs_kgts->ts_gru) |
229 | gru_load_kernel_context(bs, blade_id); | 239 | gru_load_kernel_context(bs, bid); |
230 | return bs; | 240 | return bs; |
231 | 241 | ||
232 | } | 242 | } |
@@ -255,7 +265,7 @@ static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) | |||
255 | 265 | ||
256 | BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); | 266 | BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); |
257 | preempt_disable(); | 267 | preempt_disable(); |
258 | bs = gru_lock_kernel_context(uv_numa_blade_id()); | 268 | bs = gru_lock_kernel_context(-1); |
259 | lcpu = uv_blade_processor_id(); | 269 | lcpu = uv_blade_processor_id(); |
260 | *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; | 270 | *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; |
261 | *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; | 271 | *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; |
@@ -384,13 +394,31 @@ int gru_get_cb_exception_detail(void *cb, | |||
384 | struct control_block_extended_exc_detail *excdet) | 394 | struct control_block_extended_exc_detail *excdet) |
385 | { | 395 | { |
386 | struct gru_control_block_extended *cbe; | 396 | struct gru_control_block_extended *cbe; |
387 | struct gru_blade_state *bs; | 397 | struct gru_thread_state *kgts = NULL; |
388 | int cbrnum; | 398 | unsigned long off; |
389 | 399 | int cbrnum, bid; | |
390 | bs = KCB_TO_BS(cb); | 400 | |
391 | cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb)); | 401 | /* |
402 | * Locate kgts for cb. This algorithm is SLOW but | ||
403 | * this function is rarely called (ie., almost never). | ||
404 | * Performance does not matter. | ||
405 | */ | ||
406 | for_each_possible_blade(bid) { | ||
407 | if (!gru_base[bid]) | ||
408 | break; | ||
409 | kgts = gru_base[bid]->bs_kgts; | ||
410 | if (!kgts || !kgts->ts_gru) | ||
411 | continue; | ||
412 | off = cb - kgts->ts_gru->gs_gru_base_vaddr; | ||
413 | if (off < GRU_SIZE) | ||
414 | break; | ||
415 | kgts = NULL; | ||
416 | } | ||
417 | BUG_ON(!kgts); | ||
418 | cbrnum = thread_cbr_number(kgts, get_cb_number(cb)); | ||
392 | cbe = get_cbe(GRUBASE(cb), cbrnum); | 419 | cbe = get_cbe(GRUBASE(cb), cbrnum); |
393 | gru_flush_cache(cbe); /* CBE not coherent */ | 420 | gru_flush_cache(cbe); /* CBE not coherent */ |
421 | sync_core(); | ||
394 | excdet->opc = cbe->opccpy; | 422 | excdet->opc = cbe->opccpy; |
395 | excdet->exopc = cbe->exopccpy; | 423 | excdet->exopc = cbe->exopccpy; |
396 | excdet->ecause = cbe->ecause; | 424 | excdet->ecause = cbe->ecause; |
@@ -409,8 +437,8 @@ char *gru_get_cb_exception_detail_str(int ret, void *cb, | |||
409 | if (ret > 0 && gen->istatus == CBS_EXCEPTION) { | 437 | if (ret > 0 && gen->istatus == CBS_EXCEPTION) { |
410 | gru_get_cb_exception_detail(cb, &excdet); | 438 | gru_get_cb_exception_detail(cb, &excdet); |
411 | snprintf(buf, size, | 439 | snprintf(buf, size, |
412 | "GRU exception: cb %p, opc %d, exopc %d, ecause 0x%x," | 440 | "GRU:%d exception: cb %p, opc %d, exopc %d, ecause 0x%x," |
413 | "excdet0 0x%lx, excdet1 0x%x", | 441 | "excdet0 0x%lx, excdet1 0x%x", smp_processor_id(), |
414 | gen, excdet.opc, excdet.exopc, excdet.ecause, | 442 | gen, excdet.opc, excdet.exopc, excdet.ecause, |
415 | excdet.exceptdet0, excdet.exceptdet1); | 443 | excdet.exceptdet0, excdet.exceptdet1); |
416 | } else { | 444 | } else { |
@@ -457,9 +485,10 @@ int gru_check_status_proc(void *cb) | |||
457 | int ret; | 485 | int ret; |
458 | 486 | ||
459 | ret = gen->istatus; | 487 | ret = gen->istatus; |
460 | if (ret != CBS_EXCEPTION) | 488 | if (ret == CBS_EXCEPTION) |
461 | return ret; | 489 | ret = gru_retry_exception(cb); |
462 | return gru_retry_exception(cb); | 490 | rmb(); |
491 | return ret; | ||
463 | 492 | ||
464 | } | 493 | } |
465 | 494 | ||
@@ -471,7 +500,7 @@ int gru_wait_proc(void *cb) | |||
471 | ret = gru_wait_idle_or_exception(gen); | 500 | ret = gru_wait_idle_or_exception(gen); |
472 | if (ret == CBS_EXCEPTION) | 501 | if (ret == CBS_EXCEPTION) |
473 | ret = gru_retry_exception(cb); | 502 | ret = gru_retry_exception(cb); |
474 | 503 | rmb(); | |
475 | return ret; | 504 | return ret; |
476 | } | 505 | } |
477 | 506 | ||
@@ -538,7 +567,7 @@ int gru_create_message_queue(struct gru_message_queue_desc *mqd, | |||
538 | mqd->mq = mq; | 567 | mqd->mq = mq; |
539 | mqd->mq_gpa = uv_gpa(mq); | 568 | mqd->mq_gpa = uv_gpa(mq); |
540 | mqd->qlines = qlines; | 569 | mqd->qlines = qlines; |
541 | mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid); | 570 | mqd->interrupt_pnode = nasid >> 1; |
542 | mqd->interrupt_vector = vector; | 571 | mqd->interrupt_vector = vector; |
543 | mqd->interrupt_apicid = apicid; | 572 | mqd->interrupt_apicid = apicid; |
544 | return 0; | 573 | return 0; |
@@ -598,6 +627,8 @@ static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd, | |||
598 | ret = MQE_UNEXPECTED_CB_ERR; | 627 | ret = MQE_UNEXPECTED_CB_ERR; |
599 | break; | 628 | break; |
600 | case CBSS_PAGE_OVERFLOW: | 629 | case CBSS_PAGE_OVERFLOW: |
630 | STAT(mesq_noop_page_overflow); | ||
631 | /* fallthru */ | ||
601 | default: | 632 | default: |
602 | BUG(); | 633 | BUG(); |
603 | } | 634 | } |
@@ -673,18 +704,6 @@ cberr: | |||
673 | } | 704 | } |
674 | 705 | ||
675 | /* | 706 | /* |
676 | * Send a cross-partition interrupt to the SSI that contains the target | ||
677 | * message queue. Normally, the interrupt is automatically delivered by hardware | ||
678 | * but some error conditions require explicit delivery. | ||
679 | */ | ||
680 | static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd) | ||
681 | { | ||
682 | if (mqd->interrupt_vector) | ||
683 | uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid, | ||
684 | mqd->interrupt_vector); | ||
685 | } | ||
686 | |||
687 | /* | ||
688 | * Handle a PUT failure. Note: if message was a 2-line message, one of the | 707 | * Handle a PUT failure. Note: if message was a 2-line message, one of the |
689 | * lines might have successfully have been written. Before sending the | 708 | * lines might have successfully have been written. Before sending the |
690 | * message, "present" must be cleared in BOTH lines to prevent the receiver | 709 | * message, "present" must be cleared in BOTH lines to prevent the receiver |
@@ -693,7 +712,8 @@ static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd) | |||
693 | static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, | 712 | static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, |
694 | void *mesg, int lines) | 713 | void *mesg, int lines) |
695 | { | 714 | { |
696 | unsigned long m; | 715 | unsigned long m, *val = mesg, gpa, save; |
716 | int ret; | ||
697 | 717 | ||
698 | m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); | 718 | m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); |
699 | if (lines == 2) { | 719 | if (lines == 2) { |
@@ -704,7 +724,26 @@ static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, | |||
704 | gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); | 724 | gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); |
705 | if (gru_wait(cb) != CBS_IDLE) | 725 | if (gru_wait(cb) != CBS_IDLE) |
706 | return MQE_UNEXPECTED_CB_ERR; | 726 | return MQE_UNEXPECTED_CB_ERR; |
707 | send_message_queue_interrupt(mqd); | 727 | |
728 | if (!mqd->interrupt_vector) | ||
729 | return MQE_OK; | ||
730 | |||
731 | /* | ||
732 | * Send a cross-partition interrupt to the SSI that contains the target | ||
733 | * message queue. Normally, the interrupt is automatically delivered by | ||
734 | * hardware but some error conditions require explicit delivery. | ||
735 | * Use the GRU to deliver the interrupt. Otherwise partition failures | ||
736 | * could cause unrecovered errors. | ||
737 | */ | ||
738 | gpa = uv_global_gru_mmr_address(mqd->interrupt_pnode, UVH_IPI_INT); | ||
739 | save = *val; | ||
740 | *val = uv_hub_ipi_value(mqd->interrupt_apicid, mqd->interrupt_vector, | ||
741 | dest_Fixed); | ||
742 | gru_vstore_phys(cb, gpa, gru_get_tri(mesg), IAA_REGISTER, IMA); | ||
743 | ret = gru_wait(cb); | ||
744 | *val = save; | ||
745 | if (ret != CBS_IDLE) | ||
746 | return MQE_UNEXPECTED_CB_ERR; | ||
708 | return MQE_OK; | 747 | return MQE_OK; |
709 | } | 748 | } |
710 | 749 | ||
@@ -739,6 +778,9 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd, | |||
739 | STAT(mesq_send_put_nacked); | 778 | STAT(mesq_send_put_nacked); |
740 | ret = send_message_put_nacked(cb, mqd, mesg, lines); | 779 | ret = send_message_put_nacked(cb, mqd, mesg, lines); |
741 | break; | 780 | break; |
781 | case CBSS_PAGE_OVERFLOW: | ||
782 | STAT(mesq_page_overflow); | ||
783 | /* fallthru */ | ||
742 | default: | 784 | default: |
743 | BUG(); | 785 | BUG(); |
744 | } | 786 | } |
@@ -831,7 +873,6 @@ void *gru_get_next_message(struct gru_message_queue_desc *mqd) | |||
831 | int present = mhdr->present; | 873 | int present = mhdr->present; |
832 | 874 | ||
833 | /* skip NOOP messages */ | 875 | /* skip NOOP messages */ |
834 | STAT(mesq_receive); | ||
835 | while (present == MQS_NOOP) { | 876 | while (present == MQS_NOOP) { |
836 | gru_free_message(mqd, mhdr); | 877 | gru_free_message(mqd, mhdr); |
837 | mhdr = mq->next; | 878 | mhdr = mq->next; |
@@ -851,6 +892,7 @@ void *gru_get_next_message(struct gru_message_queue_desc *mqd) | |||
851 | if (mhdr->lines == 2) | 892 | if (mhdr->lines == 2) |
852 | restore_present2(mhdr, mhdr->present2); | 893 | restore_present2(mhdr, mhdr->present2); |
853 | 894 | ||
895 | STAT(mesq_receive); | ||
854 | return mhdr; | 896 | return mhdr; |
855 | } | 897 | } |
856 | EXPORT_SYMBOL_GPL(gru_get_next_message); | 898 | EXPORT_SYMBOL_GPL(gru_get_next_message); |
@@ -858,6 +900,29 @@ EXPORT_SYMBOL_GPL(gru_get_next_message); | |||
858 | /* ---------------------- GRU DATA COPY FUNCTIONS ---------------------------*/ | 900 | /* ---------------------- GRU DATA COPY FUNCTIONS ---------------------------*/ |
859 | 901 | ||
860 | /* | 902 | /* |
903 | * Load a DW from a global GPA. The GPA can be a memory or MMR address. | ||
904 | */ | ||
905 | int gru_read_gpa(unsigned long *value, unsigned long gpa) | ||
906 | { | ||
907 | void *cb; | ||
908 | void *dsr; | ||
909 | int ret, iaa; | ||
910 | |||
911 | STAT(read_gpa); | ||
912 | if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr)) | ||
913 | return MQE_BUG_NO_RESOURCES; | ||
914 | iaa = gpa >> 62; | ||
915 | gru_vload_phys(cb, gpa, gru_get_tri(dsr), iaa, IMA); | ||
916 | ret = gru_wait(cb); | ||
917 | if (ret == CBS_IDLE) | ||
918 | *value = *(unsigned long *)dsr; | ||
919 | gru_free_cpu_resources(cb, dsr); | ||
920 | return ret; | ||
921 | } | ||
922 | EXPORT_SYMBOL_GPL(gru_read_gpa); | ||
923 | |||
924 | |||
925 | /* | ||
861 | * Copy a block of data using the GRU resources | 926 | * Copy a block of data using the GRU resources |
862 | */ | 927 | */ |
863 | int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, | 928 | int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, |
@@ -898,24 +963,24 @@ static int quicktest0(unsigned long arg) | |||
898 | 963 | ||
899 | gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); | 964 | gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); |
900 | if (gru_wait(cb) != CBS_IDLE) { | 965 | if (gru_wait(cb) != CBS_IDLE) { |
901 | printk(KERN_DEBUG "GRU quicktest0: CBR failure 1\n"); | 966 | printk(KERN_DEBUG "GRU:%d quicktest0: CBR failure 1\n", smp_processor_id()); |
902 | goto done; | 967 | goto done; |
903 | } | 968 | } |
904 | 969 | ||
905 | if (*p != MAGIC) { | 970 | if (*p != MAGIC) { |
906 | printk(KERN_DEBUG "GRU: quicktest0 bad magic 0x%lx\n", *p); | 971 | printk(KERN_DEBUG "GRU:%d quicktest0 bad magic 0x%lx\n", smp_processor_id(), *p); |
907 | goto done; | 972 | goto done; |
908 | } | 973 | } |
909 | gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); | 974 | gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); |
910 | if (gru_wait(cb) != CBS_IDLE) { | 975 | if (gru_wait(cb) != CBS_IDLE) { |
911 | printk(KERN_DEBUG "GRU quicktest0: CBR failure 2\n"); | 976 | printk(KERN_DEBUG "GRU:%d quicktest0: CBR failure 2\n", smp_processor_id()); |
912 | goto done; | 977 | goto done; |
913 | } | 978 | } |
914 | 979 | ||
915 | if (word0 != word1 || word1 != MAGIC) { | 980 | if (word0 != word1 || word1 != MAGIC) { |
916 | printk(KERN_DEBUG | 981 | printk(KERN_DEBUG |
917 | "GRU quicktest0 err: found 0x%lx, expected 0x%lx\n", | 982 | "GRU:%d quicktest0 err: found 0x%lx, expected 0x%lx\n", |
918 | word1, MAGIC); | 983 | smp_processor_id(), word1, MAGIC); |
919 | goto done; | 984 | goto done; |
920 | } | 985 | } |
921 | ret = 0; | 986 | ret = 0; |
@@ -952,8 +1017,11 @@ static int quicktest1(unsigned long arg) | |||
952 | if (ret) | 1017 | if (ret) |
953 | break; | 1018 | break; |
954 | } | 1019 | } |
955 | if (ret != MQE_QUEUE_FULL || i != 4) | 1020 | if (ret != MQE_QUEUE_FULL || i != 4) { |
1021 | printk(KERN_DEBUG "GRU:%d quicktest1: unexpect status %d, i %d\n", | ||
1022 | smp_processor_id(), ret, i); | ||
956 | goto done; | 1023 | goto done; |
1024 | } | ||
957 | 1025 | ||
958 | for (i = 0; i < 6; i++) { | 1026 | for (i = 0; i < 6; i++) { |
959 | m = gru_get_next_message(&mqd); | 1027 | m = gru_get_next_message(&mqd); |
@@ -961,7 +1029,12 @@ static int quicktest1(unsigned long arg) | |||
961 | break; | 1029 | break; |
962 | gru_free_message(&mqd, m); | 1030 | gru_free_message(&mqd, m); |
963 | } | 1031 | } |
964 | ret = (i == 4) ? 0 : -EIO; | 1032 | if (i != 4) { |
1033 | printk(KERN_DEBUG "GRU:%d quicktest2: bad message, i %d, m %p, m8 %d\n", | ||
1034 | smp_processor_id(), i, m, m ? m[8] : -1); | ||
1035 | goto done; | ||
1036 | } | ||
1037 | ret = 0; | ||
965 | 1038 | ||
966 | done: | 1039 | done: |
967 | kfree(p); | 1040 | kfree(p); |
@@ -977,6 +1050,7 @@ static int quicktest2(unsigned long arg) | |||
977 | int ret = 0; | 1050 | int ret = 0; |
978 | unsigned long *buf; | 1051 | unsigned long *buf; |
979 | void *cb0, *cb; | 1052 | void *cb0, *cb; |
1053 | struct gru_control_block_status *gen; | ||
980 | int i, k, istatus, bytes; | 1054 | int i, k, istatus, bytes; |
981 | 1055 | ||
982 | bytes = numcb * 4 * 8; | 1056 | bytes = numcb * 4 * 8; |
@@ -996,20 +1070,30 @@ static int quicktest2(unsigned long arg) | |||
996 | XTYPE_DW, 4, 1, IMA_INTERRUPT); | 1070 | XTYPE_DW, 4, 1, IMA_INTERRUPT); |
997 | 1071 | ||
998 | ret = 0; | 1072 | ret = 0; |
999 | for (k = 0; k < numcb; k++) { | 1073 | k = numcb; |
1074 | do { | ||
1000 | gru_wait_async_cbr(han); | 1075 | gru_wait_async_cbr(han); |
1001 | for (i = 0; i < numcb; i++) { | 1076 | for (i = 0; i < numcb; i++) { |
1002 | cb = cb0 + i * GRU_HANDLE_STRIDE; | 1077 | cb = cb0 + i * GRU_HANDLE_STRIDE; |
1003 | istatus = gru_check_status(cb); | 1078 | istatus = gru_check_status(cb); |
1004 | if (istatus == CBS_ACTIVE) | 1079 | if (istatus != CBS_ACTIVE && istatus != CBS_CALL_OS) |
1005 | continue; | 1080 | break; |
1006 | if (istatus == CBS_EXCEPTION) | ||
1007 | ret = -EFAULT; | ||
1008 | else if (buf[i] || buf[i + 1] || buf[i + 2] || | ||
1009 | buf[i + 3]) | ||
1010 | ret = -EIO; | ||
1011 | } | 1081 | } |
1012 | } | 1082 | if (i == numcb) |
1083 | continue; | ||
1084 | if (istatus != CBS_IDLE) { | ||
1085 | printk(KERN_DEBUG "GRU:%d quicktest2: cb %d, exception\n", smp_processor_id(), i); | ||
1086 | ret = -EFAULT; | ||
1087 | } else if (buf[4 * i] || buf[4 * i + 1] || buf[4 * i + 2] || | ||
1088 | buf[4 * i + 3]) { | ||
1089 | printk(KERN_DEBUG "GRU:%d quicktest2:cb %d, buf 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", | ||
1090 | smp_processor_id(), i, buf[4 * i], buf[4 * i + 1], buf[4 * i + 2], buf[4 * i + 3]); | ||
1091 | ret = -EIO; | ||
1092 | } | ||
1093 | k--; | ||
1094 | gen = cb; | ||
1095 | gen->istatus = CBS_CALL_OS; /* don't handle this CBR again */ | ||
1096 | } while (k); | ||
1013 | BUG_ON(cmp.done); | 1097 | BUG_ON(cmp.done); |
1014 | 1098 | ||
1015 | gru_unlock_async_resource(han); | 1099 | gru_unlock_async_resource(han); |
@@ -1019,6 +1103,22 @@ done: | |||
1019 | return ret; | 1103 | return ret; |
1020 | } | 1104 | } |
1021 | 1105 | ||
1106 | #define BUFSIZE 200 | ||
1107 | static int quicktest3(unsigned long arg) | ||
1108 | { | ||
1109 | char buf1[BUFSIZE], buf2[BUFSIZE]; | ||
1110 | int ret = 0; | ||
1111 | |||
1112 | memset(buf2, 0, sizeof(buf2)); | ||
1113 | memset(buf1, get_cycles() & 255, sizeof(buf1)); | ||
1114 | gru_copy_gpa(uv_gpa(buf2), uv_gpa(buf1), BUFSIZE); | ||
1115 | if (memcmp(buf1, buf2, BUFSIZE)) { | ||
1116 | printk(KERN_DEBUG "GRU:%d quicktest3 error\n", smp_processor_id()); | ||
1117 | ret = -EIO; | ||
1118 | } | ||
1119 | return ret; | ||
1120 | } | ||
1121 | |||
1022 | /* | 1122 | /* |
1023 | * Debugging only. User hook for various kernel tests | 1123 | * Debugging only. User hook for various kernel tests |
1024 | * of driver & gru. | 1124 | * of driver & gru. |
@@ -1037,6 +1137,9 @@ int gru_ktest(unsigned long arg) | |||
1037 | case 2: | 1137 | case 2: |
1038 | ret = quicktest2(arg); | 1138 | ret = quicktest2(arg); |
1039 | break; | 1139 | break; |
1140 | case 3: | ||
1141 | ret = quicktest3(arg); | ||
1142 | break; | ||
1040 | case 99: | 1143 | case 99: |
1041 | ret = gru_free_kernel_contexts(); | 1144 | ret = gru_free_kernel_contexts(); |
1042 | break; | 1145 | break; |
diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h index d60d34bca44d..02aa94d8484a 100644 --- a/drivers/misc/sgi-gru/grukservices.h +++ b/drivers/misc/sgi-gru/grukservices.h | |||
@@ -131,6 +131,20 @@ extern void *gru_get_next_message(struct gru_message_queue_desc *mqd); | |||
131 | 131 | ||
132 | 132 | ||
133 | /* | 133 | /* |
134 | * Read a GRU global GPA. Source can be located in a remote partition. | ||
135 | * | ||
136 | * Input: | ||
137 | * value memory address where MMR value is returned | ||
138 | * gpa source numalink physical address of GPA | ||
139 | * | ||
140 | * Output: | ||
141 | * 0 OK | ||
142 | * >0 error | ||
143 | */ | ||
144 | int gru_read_gpa(unsigned long *value, unsigned long gpa); | ||
145 | |||
146 | |||
147 | /* | ||
134 | * Copy data using the GRU. Source or destination can be located in a remote | 148 | * Copy data using the GRU. Source or destination can be located in a remote |
135 | * partition. | 149 | * partition. |
136 | * | 150 | * |
diff --git a/drivers/misc/sgi-gru/grulib.h b/drivers/misc/sgi-gru/grulib.h index 889bc442a3e8..e77d1b1f9d05 100644 --- a/drivers/misc/sgi-gru/grulib.h +++ b/drivers/misc/sgi-gru/grulib.h | |||
@@ -63,18 +63,9 @@ | |||
63 | #define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) | 63 | #define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) |
64 | #define GSEG_START(cb) ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1))) | 64 | #define GSEG_START(cb) ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1))) |
65 | 65 | ||
66 | /* | ||
67 | * Statictics kept on a per-GTS basis. | ||
68 | */ | ||
69 | struct gts_statistics { | ||
70 | unsigned long fmm_tlbdropin; | ||
71 | unsigned long upm_tlbdropin; | ||
72 | unsigned long context_stolen; | ||
73 | }; | ||
74 | |||
75 | struct gru_get_gseg_statistics_req { | 66 | struct gru_get_gseg_statistics_req { |
76 | unsigned long gseg; | 67 | unsigned long gseg; |
77 | struct gts_statistics stats; | 68 | struct gru_gseg_statistics stats; |
78 | }; | 69 | }; |
79 | 70 | ||
80 | /* | 71 | /* |
@@ -86,6 +77,7 @@ struct gru_create_context_req { | |||
86 | unsigned int control_blocks; | 77 | unsigned int control_blocks; |
87 | unsigned int maximum_thread_count; | 78 | unsigned int maximum_thread_count; |
88 | unsigned int options; | 79 | unsigned int options; |
80 | unsigned char tlb_preload_count; | ||
89 | }; | 81 | }; |
90 | 82 | ||
91 | /* | 83 | /* |
@@ -98,11 +90,12 @@ struct gru_unload_context_req { | |||
98 | /* | 90 | /* |
99 | * Structure used to set context options | 91 | * Structure used to set context options |
100 | */ | 92 | */ |
101 | enum {sco_gseg_owner, sco_cch_req_slice}; | 93 | enum {sco_gseg_owner, sco_cch_req_slice, sco_blade_chiplet}; |
102 | struct gru_set_context_option_req { | 94 | struct gru_set_context_option_req { |
103 | unsigned long gseg; | 95 | unsigned long gseg; |
104 | int op; | 96 | int op; |
105 | unsigned long val1; | 97 | int val0; |
98 | long val1; | ||
106 | }; | 99 | }; |
107 | 100 | ||
108 | /* | 101 | /* |
@@ -124,6 +117,8 @@ struct gru_dump_chiplet_state_req { | |||
124 | int ctxnum; | 117 | int ctxnum; |
125 | char data_opt; | 118 | char data_opt; |
126 | char lock_cch; | 119 | char lock_cch; |
120 | char flush_cbrs; | ||
121 | char fill[10]; | ||
127 | pid_t pid; | 122 | pid_t pid; |
128 | void *buf; | 123 | void *buf; |
129 | size_t buflen; | 124 | size_t buflen; |
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 3bc643dad606..f8538bbd0bfa 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/err.h> | ||
30 | #include <asm/uv/uv_hub.h> | 31 | #include <asm/uv/uv_hub.h> |
31 | #include "gru.h" | 32 | #include "gru.h" |
32 | #include "grutables.h" | 33 | #include "grutables.h" |
@@ -48,12 +49,20 @@ struct device *grudev = &gru_device; | |||
48 | /* | 49 | /* |
49 | * Select a gru fault map to be used by the current cpu. Note that | 50 | * Select a gru fault map to be used by the current cpu. Note that |
50 | * multiple cpus may be using the same map. | 51 | * multiple cpus may be using the same map. |
51 | * ZZZ should "shift" be used?? Depends on HT cpu numbering | ||
52 | * ZZZ should be inline but did not work on emulator | 52 | * ZZZ should be inline but did not work on emulator |
53 | */ | 53 | */ |
54 | int gru_cpu_fault_map_id(void) | 54 | int gru_cpu_fault_map_id(void) |
55 | { | 55 | { |
56 | #ifdef CONFIG_IA64 | ||
56 | return uv_blade_processor_id() % GRU_NUM_TFM; | 57 | return uv_blade_processor_id() % GRU_NUM_TFM; |
58 | #else | ||
59 | int cpu = smp_processor_id(); | ||
60 | int id, core; | ||
61 | |||
62 | core = uv_cpu_core_number(cpu); | ||
63 | id = core + UV_MAX_INT_CORES * uv_cpu_socket_number(cpu); | ||
64 | return id; | ||
65 | #endif | ||
57 | } | 66 | } |
58 | 67 | ||
59 | /*--------- ASID Management ------------------------------------------- | 68 | /*--------- ASID Management ------------------------------------------- |
@@ -286,7 +295,8 @@ static void gru_unload_mm_tracker(struct gru_state *gru, | |||
286 | void gts_drop(struct gru_thread_state *gts) | 295 | void gts_drop(struct gru_thread_state *gts) |
287 | { | 296 | { |
288 | if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { | 297 | if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { |
289 | gru_drop_mmu_notifier(gts->ts_gms); | 298 | if (gts->ts_gms) |
299 | gru_drop_mmu_notifier(gts->ts_gms); | ||
290 | kfree(gts); | 300 | kfree(gts); |
291 | STAT(gts_free); | 301 | STAT(gts_free); |
292 | } | 302 | } |
@@ -310,16 +320,18 @@ static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data | |||
310 | * Allocate a thread state structure. | 320 | * Allocate a thread state structure. |
311 | */ | 321 | */ |
312 | struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | 322 | struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, |
313 | int cbr_au_count, int dsr_au_count, int options, int tsid) | 323 | int cbr_au_count, int dsr_au_count, |
324 | unsigned char tlb_preload_count, int options, int tsid) | ||
314 | { | 325 | { |
315 | struct gru_thread_state *gts; | 326 | struct gru_thread_state *gts; |
327 | struct gru_mm_struct *gms; | ||
316 | int bytes; | 328 | int bytes; |
317 | 329 | ||
318 | bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); | 330 | bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); |
319 | bytes += sizeof(struct gru_thread_state); | 331 | bytes += sizeof(struct gru_thread_state); |
320 | gts = kmalloc(bytes, GFP_KERNEL); | 332 | gts = kmalloc(bytes, GFP_KERNEL); |
321 | if (!gts) | 333 | if (!gts) |
322 | return NULL; | 334 | return ERR_PTR(-ENOMEM); |
323 | 335 | ||
324 | STAT(gts_alloc); | 336 | STAT(gts_alloc); |
325 | memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ | 337 | memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ |
@@ -327,7 +339,10 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
327 | mutex_init(>s->ts_ctxlock); | 339 | mutex_init(>s->ts_ctxlock); |
328 | gts->ts_cbr_au_count = cbr_au_count; | 340 | gts->ts_cbr_au_count = cbr_au_count; |
329 | gts->ts_dsr_au_count = dsr_au_count; | 341 | gts->ts_dsr_au_count = dsr_au_count; |
342 | gts->ts_tlb_preload_count = tlb_preload_count; | ||
330 | gts->ts_user_options = options; | 343 | gts->ts_user_options = options; |
344 | gts->ts_user_blade_id = -1; | ||
345 | gts->ts_user_chiplet_id = -1; | ||
331 | gts->ts_tsid = tsid; | 346 | gts->ts_tsid = tsid; |
332 | gts->ts_ctxnum = NULLCTX; | 347 | gts->ts_ctxnum = NULLCTX; |
333 | gts->ts_tlb_int_select = -1; | 348 | gts->ts_tlb_int_select = -1; |
@@ -336,9 +351,10 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
336 | if (vma) { | 351 | if (vma) { |
337 | gts->ts_mm = current->mm; | 352 | gts->ts_mm = current->mm; |
338 | gts->ts_vma = vma; | 353 | gts->ts_vma = vma; |
339 | gts->ts_gms = gru_register_mmu_notifier(); | 354 | gms = gru_register_mmu_notifier(); |
340 | if (!gts->ts_gms) | 355 | if (IS_ERR(gms)) |
341 | goto err; | 356 | goto err; |
357 | gts->ts_gms = gms; | ||
342 | } | 358 | } |
343 | 359 | ||
344 | gru_dbg(grudev, "alloc gts %p\n", gts); | 360 | gru_dbg(grudev, "alloc gts %p\n", gts); |
@@ -346,7 +362,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
346 | 362 | ||
347 | err: | 363 | err: |
348 | gts_drop(gts); | 364 | gts_drop(gts); |
349 | return NULL; | 365 | return ERR_CAST(gms); |
350 | } | 366 | } |
351 | 367 | ||
352 | /* | 368 | /* |
@@ -360,6 +376,7 @@ struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid) | |||
360 | if (!vdata) | 376 | if (!vdata) |
361 | return NULL; | 377 | return NULL; |
362 | 378 | ||
379 | STAT(vdata_alloc); | ||
363 | INIT_LIST_HEAD(&vdata->vd_head); | 380 | INIT_LIST_HEAD(&vdata->vd_head); |
364 | spin_lock_init(&vdata->vd_lock); | 381 | spin_lock_init(&vdata->vd_lock); |
365 | gru_dbg(grudev, "alloc vdata %p\n", vdata); | 382 | gru_dbg(grudev, "alloc vdata %p\n", vdata); |
@@ -392,10 +409,12 @@ struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, | |||
392 | struct gru_vma_data *vdata = vma->vm_private_data; | 409 | struct gru_vma_data *vdata = vma->vm_private_data; |
393 | struct gru_thread_state *gts, *ngts; | 410 | struct gru_thread_state *gts, *ngts; |
394 | 411 | ||
395 | gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, | 412 | gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, |
413 | vdata->vd_dsr_au_count, | ||
414 | vdata->vd_tlb_preload_count, | ||
396 | vdata->vd_user_options, tsid); | 415 | vdata->vd_user_options, tsid); |
397 | if (!gts) | 416 | if (IS_ERR(gts)) |
398 | return NULL; | 417 | return gts; |
399 | 418 | ||
400 | spin_lock(&vdata->vd_lock); | 419 | spin_lock(&vdata->vd_lock); |
401 | ngts = gru_find_current_gts_nolock(vdata, tsid); | 420 | ngts = gru_find_current_gts_nolock(vdata, tsid); |
@@ -493,6 +512,9 @@ static void gru_load_context_data(void *save, void *grubase, int ctxnum, | |||
493 | memset(cbe + i * GRU_HANDLE_STRIDE, 0, | 512 | memset(cbe + i * GRU_HANDLE_STRIDE, 0, |
494 | GRU_CACHE_LINE_BYTES); | 513 | GRU_CACHE_LINE_BYTES); |
495 | } | 514 | } |
515 | /* Flush CBE to hide race in context restart */ | ||
516 | mb(); | ||
517 | gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE); | ||
496 | cb += GRU_HANDLE_STRIDE; | 518 | cb += GRU_HANDLE_STRIDE; |
497 | } | 519 | } |
498 | 520 | ||
@@ -513,6 +535,12 @@ static void gru_unload_context_data(void *save, void *grubase, int ctxnum, | |||
513 | cb = gseg + GRU_CB_BASE; | 535 | cb = gseg + GRU_CB_BASE; |
514 | cbe = grubase + GRU_CBE_BASE; | 536 | cbe = grubase + GRU_CBE_BASE; |
515 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; | 537 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; |
538 | |||
539 | /* CBEs may not be coherent. Flush them from cache */ | ||
540 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) | ||
541 | gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE); | ||
542 | mb(); /* Let the CL flush complete */ | ||
543 | |||
516 | gru_prefetch_context(gseg, cb, cbe, cbrmap, length); | 544 | gru_prefetch_context(gseg, cb, cbe, cbrmap, length); |
517 | 545 | ||
518 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { | 546 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { |
@@ -533,7 +561,8 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) | |||
533 | zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); | 561 | zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); |
534 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | 562 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); |
535 | 563 | ||
536 | gru_dbg(grudev, "gts %p\n", gts); | 564 | gru_dbg(grudev, "gts %p, cbrmap 0x%lx, dsrmap 0x%lx\n", |
565 | gts, gts->ts_cbr_map, gts->ts_dsr_map); | ||
537 | lock_cch_handle(cch); | 566 | lock_cch_handle(cch); |
538 | if (cch_interrupt_sync(cch)) | 567 | if (cch_interrupt_sync(cch)) |
539 | BUG(); | 568 | BUG(); |
@@ -549,7 +578,6 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) | |||
549 | 578 | ||
550 | if (cch_deallocate(cch)) | 579 | if (cch_deallocate(cch)) |
551 | BUG(); | 580 | BUG(); |
552 | gts->ts_force_unload = 0; /* ts_force_unload locked by CCH lock */ | ||
553 | unlock_cch_handle(cch); | 581 | unlock_cch_handle(cch); |
554 | 582 | ||
555 | gru_free_gru_context(gts); | 583 | gru_free_gru_context(gts); |
@@ -565,9 +593,7 @@ void gru_load_context(struct gru_thread_state *gts) | |||
565 | struct gru_context_configuration_handle *cch; | 593 | struct gru_context_configuration_handle *cch; |
566 | int i, err, asid, ctxnum = gts->ts_ctxnum; | 594 | int i, err, asid, ctxnum = gts->ts_ctxnum; |
567 | 595 | ||
568 | gru_dbg(grudev, "gts %p\n", gts); | ||
569 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | 596 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); |
570 | |||
571 | lock_cch_handle(cch); | 597 | lock_cch_handle(cch); |
572 | cch->tfm_fault_bit_enable = | 598 | cch->tfm_fault_bit_enable = |
573 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL | 599 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL |
@@ -591,6 +617,7 @@ void gru_load_context(struct gru_thread_state *gts) | |||
591 | cch->unmap_enable = 1; | 617 | cch->unmap_enable = 1; |
592 | cch->tfm_done_bit_enable = 1; | 618 | cch->tfm_done_bit_enable = 1; |
593 | cch->cb_int_enable = 1; | 619 | cch->cb_int_enable = 1; |
620 | cch->tlb_int_select = 0; /* For now, ints go to cpu 0 */ | ||
594 | } else { | 621 | } else { |
595 | cch->unmap_enable = 0; | 622 | cch->unmap_enable = 0; |
596 | cch->tfm_done_bit_enable = 0; | 623 | cch->tfm_done_bit_enable = 0; |
@@ -616,17 +643,18 @@ void gru_load_context(struct gru_thread_state *gts) | |||
616 | if (cch_start(cch)) | 643 | if (cch_start(cch)) |
617 | BUG(); | 644 | BUG(); |
618 | unlock_cch_handle(cch); | 645 | unlock_cch_handle(cch); |
646 | |||
647 | gru_dbg(grudev, "gid %d, gts %p, cbrmap 0x%lx, dsrmap 0x%lx, tie %d, tis %d\n", | ||
648 | gts->ts_gru->gs_gid, gts, gts->ts_cbr_map, gts->ts_dsr_map, | ||
649 | (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR), gts->ts_tlb_int_select); | ||
619 | } | 650 | } |
620 | 651 | ||
621 | /* | 652 | /* |
622 | * Update fields in an active CCH: | 653 | * Update fields in an active CCH: |
623 | * - retarget interrupts on local blade | 654 | * - retarget interrupts on local blade |
624 | * - update sizeavail mask | 655 | * - update sizeavail mask |
625 | * - force a delayed context unload by clearing the CCH asids. This | ||
626 | * forces TLB misses for new GRU instructions. The context is unloaded | ||
627 | * when the next TLB miss occurs. | ||
628 | */ | 656 | */ |
629 | int gru_update_cch(struct gru_thread_state *gts, int force_unload) | 657 | int gru_update_cch(struct gru_thread_state *gts) |
630 | { | 658 | { |
631 | struct gru_context_configuration_handle *cch; | 659 | struct gru_context_configuration_handle *cch; |
632 | struct gru_state *gru = gts->ts_gru; | 660 | struct gru_state *gru = gts->ts_gru; |
@@ -640,21 +668,13 @@ int gru_update_cch(struct gru_thread_state *gts, int force_unload) | |||
640 | goto exit; | 668 | goto exit; |
641 | if (cch_interrupt(cch)) | 669 | if (cch_interrupt(cch)) |
642 | BUG(); | 670 | BUG(); |
643 | if (!force_unload) { | 671 | for (i = 0; i < 8; i++) |
644 | for (i = 0; i < 8; i++) | 672 | cch->sizeavail[i] = gts->ts_sizeavail; |
645 | cch->sizeavail[i] = gts->ts_sizeavail; | 673 | gts->ts_tlb_int_select = gru_cpu_fault_map_id(); |
646 | gts->ts_tlb_int_select = gru_cpu_fault_map_id(); | 674 | cch->tlb_int_select = gru_cpu_fault_map_id(); |
647 | cch->tlb_int_select = gru_cpu_fault_map_id(); | 675 | cch->tfm_fault_bit_enable = |
648 | cch->tfm_fault_bit_enable = | 676 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL |
649 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL | 677 | || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); |
650 | || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); | ||
651 | } else { | ||
652 | for (i = 0; i < 8; i++) | ||
653 | cch->asid[i] = 0; | ||
654 | cch->tfm_fault_bit_enable = 0; | ||
655 | cch->tlb_int_enable = 0; | ||
656 | gts->ts_force_unload = 1; | ||
657 | } | ||
658 | if (cch_start(cch)) | 678 | if (cch_start(cch)) |
659 | BUG(); | 679 | BUG(); |
660 | ret = 1; | 680 | ret = 1; |
@@ -679,7 +699,54 @@ static int gru_retarget_intr(struct gru_thread_state *gts) | |||
679 | 699 | ||
680 | gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, | 700 | gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, |
681 | gru_cpu_fault_map_id()); | 701 | gru_cpu_fault_map_id()); |
682 | return gru_update_cch(gts, 0); | 702 | return gru_update_cch(gts); |
703 | } | ||
704 | |||
705 | /* | ||
706 | * Check if a GRU context is allowed to use a specific chiplet. By default | ||
707 | * a context is assigned to any blade-local chiplet. However, users can | ||
708 | * override this. | ||
709 | * Returns 1 if assignment allowed, 0 otherwise | ||
710 | */ | ||
711 | static int gru_check_chiplet_assignment(struct gru_state *gru, | ||
712 | struct gru_thread_state *gts) | ||
713 | { | ||
714 | int blade_id; | ||
715 | int chiplet_id; | ||
716 | |||
717 | blade_id = gts->ts_user_blade_id; | ||
718 | if (blade_id < 0) | ||
719 | blade_id = uv_numa_blade_id(); | ||
720 | |||
721 | chiplet_id = gts->ts_user_chiplet_id; | ||
722 | return gru->gs_blade_id == blade_id && | ||
723 | (chiplet_id < 0 || chiplet_id == gru->gs_chiplet_id); | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * Unload the gru context if it is not assigned to the correct blade or | ||
728 | * chiplet. Misassignment can occur if the process migrates to a different | ||
729 | * blade or if the user changes the selected blade/chiplet. | ||
730 | */ | ||
731 | void gru_check_context_placement(struct gru_thread_state *gts) | ||
732 | { | ||
733 | struct gru_state *gru; | ||
734 | |||
735 | /* | ||
736 | * If the current task is the context owner, verify that the | ||
737 | * context is correctly placed. This test is skipped for non-owner | ||
738 | * references. Pthread apps use non-owner references to the CBRs. | ||
739 | */ | ||
740 | gru = gts->ts_gru; | ||
741 | if (!gru || gts->ts_tgid_owner != current->tgid) | ||
742 | return; | ||
743 | |||
744 | if (!gru_check_chiplet_assignment(gru, gts)) { | ||
745 | STAT(check_context_unload); | ||
746 | gru_unload_context(gts, 1); | ||
747 | } else if (gru_retarget_intr(gts)) { | ||
748 | STAT(check_context_retarget_intr); | ||
749 | } | ||
683 | } | 750 | } |
684 | 751 | ||
685 | 752 | ||
@@ -712,13 +779,17 @@ static void gts_stolen(struct gru_thread_state *gts, | |||
712 | } | 779 | } |
713 | } | 780 | } |
714 | 781 | ||
715 | void gru_steal_context(struct gru_thread_state *gts, int blade_id) | 782 | void gru_steal_context(struct gru_thread_state *gts) |
716 | { | 783 | { |
717 | struct gru_blade_state *blade; | 784 | struct gru_blade_state *blade; |
718 | struct gru_state *gru, *gru0; | 785 | struct gru_state *gru, *gru0; |
719 | struct gru_thread_state *ngts = NULL; | 786 | struct gru_thread_state *ngts = NULL; |
720 | int ctxnum, ctxnum0, flag = 0, cbr, dsr; | 787 | int ctxnum, ctxnum0, flag = 0, cbr, dsr; |
788 | int blade_id; | ||
721 | 789 | ||
790 | blade_id = gts->ts_user_blade_id; | ||
791 | if (blade_id < 0) | ||
792 | blade_id = uv_numa_blade_id(); | ||
722 | cbr = gts->ts_cbr_au_count; | 793 | cbr = gts->ts_cbr_au_count; |
723 | dsr = gts->ts_dsr_au_count; | 794 | dsr = gts->ts_dsr_au_count; |
724 | 795 | ||
@@ -729,35 +800,39 @@ void gru_steal_context(struct gru_thread_state *gts, int blade_id) | |||
729 | gru = blade->bs_lru_gru; | 800 | gru = blade->bs_lru_gru; |
730 | if (ctxnum == 0) | 801 | if (ctxnum == 0) |
731 | gru = next_gru(blade, gru); | 802 | gru = next_gru(blade, gru); |
803 | blade->bs_lru_gru = gru; | ||
804 | blade->bs_lru_ctxnum = ctxnum; | ||
732 | ctxnum0 = ctxnum; | 805 | ctxnum0 = ctxnum; |
733 | gru0 = gru; | 806 | gru0 = gru; |
734 | while (1) { | 807 | while (1) { |
735 | if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) | 808 | if (gru_check_chiplet_assignment(gru, gts)) { |
736 | break; | 809 | if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) |
737 | spin_lock(&gru->gs_lock); | ||
738 | for (; ctxnum < GRU_NUM_CCH; ctxnum++) { | ||
739 | if (flag && gru == gru0 && ctxnum == ctxnum0) | ||
740 | break; | 810 | break; |
741 | ngts = gru->gs_gts[ctxnum]; | 811 | spin_lock(&gru->gs_lock); |
742 | /* | 812 | for (; ctxnum < GRU_NUM_CCH; ctxnum++) { |
743 | * We are grabbing locks out of order, so trylock is | 813 | if (flag && gru == gru0 && ctxnum == ctxnum0) |
744 | * needed. GTSs are usually not locked, so the odds of | 814 | break; |
745 | * success are high. If trylock fails, try to steal a | 815 | ngts = gru->gs_gts[ctxnum]; |
746 | * different GSEG. | 816 | /* |
747 | */ | 817 | * We are grabbing locks out of order, so trylock is |
748 | if (ngts && is_gts_stealable(ngts, blade)) | 818 | * needed. GTSs are usually not locked, so the odds of |
819 | * success are high. If trylock fails, try to steal a | ||
820 | * different GSEG. | ||
821 | */ | ||
822 | if (ngts && is_gts_stealable(ngts, blade)) | ||
823 | break; | ||
824 | ngts = NULL; | ||
825 | } | ||
826 | spin_unlock(&gru->gs_lock); | ||
827 | if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) | ||
749 | break; | 828 | break; |
750 | ngts = NULL; | ||
751 | flag = 1; | ||
752 | } | 829 | } |
753 | spin_unlock(&gru->gs_lock); | 830 | if (flag && gru == gru0) |
754 | if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) | ||
755 | break; | 831 | break; |
832 | flag = 1; | ||
756 | ctxnum = 0; | 833 | ctxnum = 0; |
757 | gru = next_gru(blade, gru); | 834 | gru = next_gru(blade, gru); |
758 | } | 835 | } |
759 | blade->bs_lru_gru = gru; | ||
760 | blade->bs_lru_ctxnum = ctxnum; | ||
761 | spin_unlock(&blade->bs_lock); | 836 | spin_unlock(&blade->bs_lock); |
762 | 837 | ||
763 | if (ngts) { | 838 | if (ngts) { |
@@ -776,19 +851,34 @@ void gru_steal_context(struct gru_thread_state *gts, int blade_id) | |||
776 | } | 851 | } |
777 | 852 | ||
778 | /* | 853 | /* |
854 | * Assign a gru context. | ||
855 | */ | ||
856 | static int gru_assign_context_number(struct gru_state *gru) | ||
857 | { | ||
858 | int ctxnum; | ||
859 | |||
860 | ctxnum = find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); | ||
861 | __set_bit(ctxnum, &gru->gs_context_map); | ||
862 | return ctxnum; | ||
863 | } | ||
864 | |||
865 | /* | ||
779 | * Scan the GRUs on the local blade & assign a GRU context. | 866 | * Scan the GRUs on the local blade & assign a GRU context. |
780 | */ | 867 | */ |
781 | struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, | 868 | struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) |
782 | int blade) | ||
783 | { | 869 | { |
784 | struct gru_state *gru, *grux; | 870 | struct gru_state *gru, *grux; |
785 | int i, max_active_contexts; | 871 | int i, max_active_contexts; |
872 | int blade_id = gts->ts_user_blade_id; | ||
786 | 873 | ||
787 | 874 | if (blade_id < 0) | |
875 | blade_id = uv_numa_blade_id(); | ||
788 | again: | 876 | again: |
789 | gru = NULL; | 877 | gru = NULL; |
790 | max_active_contexts = GRU_NUM_CCH; | 878 | max_active_contexts = GRU_NUM_CCH; |
791 | for_each_gru_on_blade(grux, blade, i) { | 879 | for_each_gru_on_blade(grux, blade_id, i) { |
880 | if (!gru_check_chiplet_assignment(grux, gts)) | ||
881 | continue; | ||
792 | if (check_gru_resources(grux, gts->ts_cbr_au_count, | 882 | if (check_gru_resources(grux, gts->ts_cbr_au_count, |
793 | gts->ts_dsr_au_count, | 883 | gts->ts_dsr_au_count, |
794 | max_active_contexts)) { | 884 | max_active_contexts)) { |
@@ -809,12 +899,9 @@ again: | |||
809 | reserve_gru_resources(gru, gts); | 899 | reserve_gru_resources(gru, gts); |
810 | gts->ts_gru = gru; | 900 | gts->ts_gru = gru; |
811 | gts->ts_blade = gru->gs_blade_id; | 901 | gts->ts_blade = gru->gs_blade_id; |
812 | gts->ts_ctxnum = | 902 | gts->ts_ctxnum = gru_assign_context_number(gru); |
813 | find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); | ||
814 | BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); | ||
815 | atomic_inc(>s->ts_refcnt); | 903 | atomic_inc(>s->ts_refcnt); |
816 | gru->gs_gts[gts->ts_ctxnum] = gts; | 904 | gru->gs_gts[gts->ts_ctxnum] = gts; |
817 | __set_bit(gts->ts_ctxnum, &gru->gs_context_map); | ||
818 | spin_unlock(&gru->gs_lock); | 905 | spin_unlock(&gru->gs_lock); |
819 | 906 | ||
820 | STAT(assign_context); | 907 | STAT(assign_context); |
@@ -842,7 +929,6 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
842 | { | 929 | { |
843 | struct gru_thread_state *gts; | 930 | struct gru_thread_state *gts; |
844 | unsigned long paddr, vaddr; | 931 | unsigned long paddr, vaddr; |
845 | int blade_id; | ||
846 | 932 | ||
847 | vaddr = (unsigned long)vmf->virtual_address; | 933 | vaddr = (unsigned long)vmf->virtual_address; |
848 | gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", | 934 | gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", |
@@ -857,28 +943,18 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
857 | again: | 943 | again: |
858 | mutex_lock(>s->ts_ctxlock); | 944 | mutex_lock(>s->ts_ctxlock); |
859 | preempt_disable(); | 945 | preempt_disable(); |
860 | blade_id = uv_numa_blade_id(); | ||
861 | 946 | ||
862 | if (gts->ts_gru) { | 947 | gru_check_context_placement(gts); |
863 | if (gts->ts_gru->gs_blade_id != blade_id) { | ||
864 | STAT(migrated_nopfn_unload); | ||
865 | gru_unload_context(gts, 1); | ||
866 | } else { | ||
867 | if (gru_retarget_intr(gts)) | ||
868 | STAT(migrated_nopfn_retarget); | ||
869 | } | ||
870 | } | ||
871 | 948 | ||
872 | if (!gts->ts_gru) { | 949 | if (!gts->ts_gru) { |
873 | STAT(load_user_context); | 950 | STAT(load_user_context); |
874 | if (!gru_assign_gru_context(gts, blade_id)) { | 951 | if (!gru_assign_gru_context(gts)) { |
875 | preempt_enable(); | 952 | preempt_enable(); |
876 | mutex_unlock(>s->ts_ctxlock); | 953 | mutex_unlock(>s->ts_ctxlock); |
877 | set_current_state(TASK_INTERRUPTIBLE); | 954 | set_current_state(TASK_INTERRUPTIBLE); |
878 | schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ | 955 | schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ |
879 | blade_id = uv_numa_blade_id(); | ||
880 | if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) | 956 | if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) |
881 | gru_steal_context(gts, blade_id); | 957 | gru_steal_context(gts); |
882 | goto again; | 958 | goto again; |
883 | } | 959 | } |
884 | gru_load_context(gts); | 960 | gru_load_context(gts); |
diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 3f2375c5ba5b..7768b87d995b 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c | |||
@@ -36,8 +36,7 @@ static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id) | |||
36 | { | 36 | { |
37 | unsigned long val = atomic_long_read(v); | 37 | unsigned long val = atomic_long_read(v); |
38 | 38 | ||
39 | if (val) | 39 | seq_printf(s, "%16lu %s\n", val, id); |
40 | seq_printf(s, "%16lu %s\n", val, id); | ||
41 | } | 40 | } |
42 | 41 | ||
43 | static int statistics_show(struct seq_file *s, void *p) | 42 | static int statistics_show(struct seq_file *s, void *p) |
@@ -46,7 +45,8 @@ static int statistics_show(struct seq_file *s, void *p) | |||
46 | printstat(s, vdata_free); | 45 | printstat(s, vdata_free); |
47 | printstat(s, gts_alloc); | 46 | printstat(s, gts_alloc); |
48 | printstat(s, gts_free); | 47 | printstat(s, gts_free); |
49 | printstat(s, vdata_double_alloc); | 48 | printstat(s, gms_alloc); |
49 | printstat(s, gms_free); | ||
50 | printstat(s, gts_double_allocate); | 50 | printstat(s, gts_double_allocate); |
51 | printstat(s, assign_context); | 51 | printstat(s, assign_context); |
52 | printstat(s, assign_context_failed); | 52 | printstat(s, assign_context_failed); |
@@ -59,28 +59,25 @@ static int statistics_show(struct seq_file *s, void *p) | |||
59 | printstat(s, steal_kernel_context); | 59 | printstat(s, steal_kernel_context); |
60 | printstat(s, steal_context_failed); | 60 | printstat(s, steal_context_failed); |
61 | printstat(s, nopfn); | 61 | printstat(s, nopfn); |
62 | printstat(s, break_cow); | ||
63 | printstat(s, asid_new); | 62 | printstat(s, asid_new); |
64 | printstat(s, asid_next); | 63 | printstat(s, asid_next); |
65 | printstat(s, asid_wrap); | 64 | printstat(s, asid_wrap); |
66 | printstat(s, asid_reuse); | 65 | printstat(s, asid_reuse); |
67 | printstat(s, intr); | 66 | printstat(s, intr); |
67 | printstat(s, intr_cbr); | ||
68 | printstat(s, intr_tfh); | ||
69 | printstat(s, intr_spurious); | ||
68 | printstat(s, intr_mm_lock_failed); | 70 | printstat(s, intr_mm_lock_failed); |
69 | printstat(s, call_os); | 71 | printstat(s, call_os); |
70 | printstat(s, call_os_offnode_reference); | ||
71 | printstat(s, call_os_check_for_bug); | ||
72 | printstat(s, call_os_wait_queue); | 72 | printstat(s, call_os_wait_queue); |
73 | printstat(s, user_flush_tlb); | 73 | printstat(s, user_flush_tlb); |
74 | printstat(s, user_unload_context); | 74 | printstat(s, user_unload_context); |
75 | printstat(s, user_exception); | 75 | printstat(s, user_exception); |
76 | printstat(s, set_context_option); | 76 | printstat(s, set_context_option); |
77 | printstat(s, migrate_check); | 77 | printstat(s, check_context_retarget_intr); |
78 | printstat(s, migrated_retarget); | 78 | printstat(s, check_context_unload); |
79 | printstat(s, migrated_unload); | ||
80 | printstat(s, migrated_unload_delay); | ||
81 | printstat(s, migrated_nopfn_retarget); | ||
82 | printstat(s, migrated_nopfn_unload); | ||
83 | printstat(s, tlb_dropin); | 79 | printstat(s, tlb_dropin); |
80 | printstat(s, tlb_preload_page); | ||
84 | printstat(s, tlb_dropin_fail_no_asid); | 81 | printstat(s, tlb_dropin_fail_no_asid); |
85 | printstat(s, tlb_dropin_fail_upm); | 82 | printstat(s, tlb_dropin_fail_upm); |
86 | printstat(s, tlb_dropin_fail_invalid); | 83 | printstat(s, tlb_dropin_fail_invalid); |
@@ -88,16 +85,15 @@ static int statistics_show(struct seq_file *s, void *p) | |||
88 | printstat(s, tlb_dropin_fail_idle); | 85 | printstat(s, tlb_dropin_fail_idle); |
89 | printstat(s, tlb_dropin_fail_fmm); | 86 | printstat(s, tlb_dropin_fail_fmm); |
90 | printstat(s, tlb_dropin_fail_no_exception); | 87 | printstat(s, tlb_dropin_fail_no_exception); |
91 | printstat(s, tlb_dropin_fail_no_exception_war); | ||
92 | printstat(s, tfh_stale_on_fault); | 88 | printstat(s, tfh_stale_on_fault); |
93 | printstat(s, mmu_invalidate_range); | 89 | printstat(s, mmu_invalidate_range); |
94 | printstat(s, mmu_invalidate_page); | 90 | printstat(s, mmu_invalidate_page); |
95 | printstat(s, mmu_clear_flush_young); | ||
96 | printstat(s, flush_tlb); | 91 | printstat(s, flush_tlb); |
97 | printstat(s, flush_tlb_gru); | 92 | printstat(s, flush_tlb_gru); |
98 | printstat(s, flush_tlb_gru_tgh); | 93 | printstat(s, flush_tlb_gru_tgh); |
99 | printstat(s, flush_tlb_gru_zero_asid); | 94 | printstat(s, flush_tlb_gru_zero_asid); |
100 | printstat(s, copy_gpa); | 95 | printstat(s, copy_gpa); |
96 | printstat(s, read_gpa); | ||
101 | printstat(s, mesq_receive); | 97 | printstat(s, mesq_receive); |
102 | printstat(s, mesq_receive_none); | 98 | printstat(s, mesq_receive_none); |
103 | printstat(s, mesq_send); | 99 | printstat(s, mesq_send); |
@@ -108,7 +104,6 @@ static int statistics_show(struct seq_file *s, void *p) | |||
108 | printstat(s, mesq_send_qlimit_reached); | 104 | printstat(s, mesq_send_qlimit_reached); |
109 | printstat(s, mesq_send_amo_nacked); | 105 | printstat(s, mesq_send_amo_nacked); |
110 | printstat(s, mesq_send_put_nacked); | 106 | printstat(s, mesq_send_put_nacked); |
111 | printstat(s, mesq_qf_not_full); | ||
112 | printstat(s, mesq_qf_locked); | 107 | printstat(s, mesq_qf_locked); |
113 | printstat(s, mesq_qf_noop_not_full); | 108 | printstat(s, mesq_qf_noop_not_full); |
114 | printstat(s, mesq_qf_switch_head_failed); | 109 | printstat(s, mesq_qf_switch_head_failed); |
@@ -118,6 +113,7 @@ static int statistics_show(struct seq_file *s, void *p) | |||
118 | printstat(s, mesq_noop_qlimit_reached); | 113 | printstat(s, mesq_noop_qlimit_reached); |
119 | printstat(s, mesq_noop_amo_nacked); | 114 | printstat(s, mesq_noop_amo_nacked); |
120 | printstat(s, mesq_noop_put_nacked); | 115 | printstat(s, mesq_noop_put_nacked); |
116 | printstat(s, mesq_noop_page_overflow); | ||
121 | return 0; | 117 | return 0; |
122 | } | 118 | } |
123 | 119 | ||
@@ -133,8 +129,10 @@ static int mcs_statistics_show(struct seq_file *s, void *p) | |||
133 | int op; | 129 | int op; |
134 | unsigned long total, count, max; | 130 | unsigned long total, count, max; |
135 | static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt", | 131 | static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt", |
136 | "cch_interrupt_sync", "cch_deallocate", "tgh_invalidate"}; | 132 | "cch_interrupt_sync", "cch_deallocate", "tfh_write_only", |
133 | "tfh_write_restart", "tgh_invalidate"}; | ||
137 | 134 | ||
135 | seq_printf(s, "%-20s%12s%12s%12s\n", "#id", "count", "aver-clks", "max-clks"); | ||
138 | for (op = 0; op < mcsop_last; op++) { | 136 | for (op = 0; op < mcsop_last; op++) { |
139 | count = atomic_long_read(&mcs_op_statistics[op].count); | 137 | count = atomic_long_read(&mcs_op_statistics[op].count); |
140 | total = atomic_long_read(&mcs_op_statistics[op].total); | 138 | total = atomic_long_read(&mcs_op_statistics[op].total); |
@@ -154,6 +152,7 @@ static ssize_t mcs_statistics_write(struct file *file, | |||
154 | 152 | ||
155 | static int options_show(struct seq_file *s, void *p) | 153 | static int options_show(struct seq_file *s, void *p) |
156 | { | 154 | { |
155 | seq_printf(s, "#bitmask: 1=trace, 2=statistics\n"); | ||
157 | seq_printf(s, "0x%lx\n", gru_options); | 156 | seq_printf(s, "0x%lx\n", gru_options); |
158 | return 0; | 157 | return 0; |
159 | } | 158 | } |
@@ -183,16 +182,17 @@ static int cch_seq_show(struct seq_file *file, void *data) | |||
183 | const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" }; | 182 | const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" }; |
184 | 183 | ||
185 | if (gid == 0) | 184 | if (gid == 0) |
186 | seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid", | 185 | seq_printf(file, "#%5s%5s%6s%7s%9s%6s%8s%8s\n", "gid", "bid", |
187 | "ctx#", "pid", "cbrs", "dsbytes", "mode"); | 186 | "ctx#", "asid", "pid", "cbrs", "dsbytes", "mode"); |
188 | if (gru) | 187 | if (gru) |
189 | for (i = 0; i < GRU_NUM_CCH; i++) { | 188 | for (i = 0; i < GRU_NUM_CCH; i++) { |
190 | ts = gru->gs_gts[i]; | 189 | ts = gru->gs_gts[i]; |
191 | if (!ts) | 190 | if (!ts) |
192 | continue; | 191 | continue; |
193 | seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n", | 192 | seq_printf(file, " %5d%5d%6d%7d%9d%6d%8d%8s\n", |
194 | gru->gs_gid, gru->gs_blade_id, i, | 193 | gru->gs_gid, gru->gs_blade_id, i, |
195 | ts->ts_tgid_owner, | 194 | is_kernel_context(ts) ? 0 : ts->ts_gms->ms_asids[gid].mt_asid, |
195 | is_kernel_context(ts) ? 0 : ts->ts_tgid_owner, | ||
196 | ts->ts_cbr_au_count * GRU_CBR_AU_SIZE, | 196 | ts->ts_cbr_au_count * GRU_CBR_AU_SIZE, |
197 | ts->ts_cbr_au_count * GRU_DSR_AU_BYTES, | 197 | ts->ts_cbr_au_count * GRU_DSR_AU_BYTES, |
198 | mode[ts->ts_user_options & | 198 | mode[ts->ts_user_options & |
@@ -355,7 +355,7 @@ static void delete_proc_files(void) | |||
355 | for (p = proc_files; p->name; p++) | 355 | for (p = proc_files; p->name; p++) |
356 | if (p->entry) | 356 | if (p->entry) |
357 | remove_proc_entry(p->name, proc_gru); | 357 | remove_proc_entry(p->name, proc_gru); |
358 | remove_proc_entry("gru", NULL); | 358 | remove_proc_entry("gru", proc_gru->parent); |
359 | } | 359 | } |
360 | } | 360 | } |
361 | 361 | ||
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 46990bcfa536..02a77b8b8eef 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h | |||
@@ -161,7 +161,7 @@ extern unsigned int gru_max_gids; | |||
161 | #define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) | 161 | #define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) |
162 | 162 | ||
163 | #define GRU_DRIVER_ID_STR "SGI GRU Device Driver" | 163 | #define GRU_DRIVER_ID_STR "SGI GRU Device Driver" |
164 | #define GRU_DRIVER_VERSION_STR "0.80" | 164 | #define GRU_DRIVER_VERSION_STR "0.85" |
165 | 165 | ||
166 | /* | 166 | /* |
167 | * GRU statistics. | 167 | * GRU statistics. |
@@ -171,7 +171,8 @@ struct gru_stats_s { | |||
171 | atomic_long_t vdata_free; | 171 | atomic_long_t vdata_free; |
172 | atomic_long_t gts_alloc; | 172 | atomic_long_t gts_alloc; |
173 | atomic_long_t gts_free; | 173 | atomic_long_t gts_free; |
174 | atomic_long_t vdata_double_alloc; | 174 | atomic_long_t gms_alloc; |
175 | atomic_long_t gms_free; | ||
175 | atomic_long_t gts_double_allocate; | 176 | atomic_long_t gts_double_allocate; |
176 | atomic_long_t assign_context; | 177 | atomic_long_t assign_context; |
177 | atomic_long_t assign_context_failed; | 178 | atomic_long_t assign_context_failed; |
@@ -184,28 +185,25 @@ struct gru_stats_s { | |||
184 | atomic_long_t steal_kernel_context; | 185 | atomic_long_t steal_kernel_context; |
185 | atomic_long_t steal_context_failed; | 186 | atomic_long_t steal_context_failed; |
186 | atomic_long_t nopfn; | 187 | atomic_long_t nopfn; |
187 | atomic_long_t break_cow; | ||
188 | atomic_long_t asid_new; | 188 | atomic_long_t asid_new; |
189 | atomic_long_t asid_next; | 189 | atomic_long_t asid_next; |
190 | atomic_long_t asid_wrap; | 190 | atomic_long_t asid_wrap; |
191 | atomic_long_t asid_reuse; | 191 | atomic_long_t asid_reuse; |
192 | atomic_long_t intr; | 192 | atomic_long_t intr; |
193 | atomic_long_t intr_cbr; | ||
194 | atomic_long_t intr_tfh; | ||
195 | atomic_long_t intr_spurious; | ||
193 | atomic_long_t intr_mm_lock_failed; | 196 | atomic_long_t intr_mm_lock_failed; |
194 | atomic_long_t call_os; | 197 | atomic_long_t call_os; |
195 | atomic_long_t call_os_offnode_reference; | ||
196 | atomic_long_t call_os_check_for_bug; | ||
197 | atomic_long_t call_os_wait_queue; | 198 | atomic_long_t call_os_wait_queue; |
198 | atomic_long_t user_flush_tlb; | 199 | atomic_long_t user_flush_tlb; |
199 | atomic_long_t user_unload_context; | 200 | atomic_long_t user_unload_context; |
200 | atomic_long_t user_exception; | 201 | atomic_long_t user_exception; |
201 | atomic_long_t set_context_option; | 202 | atomic_long_t set_context_option; |
202 | atomic_long_t migrate_check; | 203 | atomic_long_t check_context_retarget_intr; |
203 | atomic_long_t migrated_retarget; | 204 | atomic_long_t check_context_unload; |
204 | atomic_long_t migrated_unload; | ||
205 | atomic_long_t migrated_unload_delay; | ||
206 | atomic_long_t migrated_nopfn_retarget; | ||
207 | atomic_long_t migrated_nopfn_unload; | ||
208 | atomic_long_t tlb_dropin; | 205 | atomic_long_t tlb_dropin; |
206 | atomic_long_t tlb_preload_page; | ||
209 | atomic_long_t tlb_dropin_fail_no_asid; | 207 | atomic_long_t tlb_dropin_fail_no_asid; |
210 | atomic_long_t tlb_dropin_fail_upm; | 208 | atomic_long_t tlb_dropin_fail_upm; |
211 | atomic_long_t tlb_dropin_fail_invalid; | 209 | atomic_long_t tlb_dropin_fail_invalid; |
@@ -213,17 +211,16 @@ struct gru_stats_s { | |||
213 | atomic_long_t tlb_dropin_fail_idle; | 211 | atomic_long_t tlb_dropin_fail_idle; |
214 | atomic_long_t tlb_dropin_fail_fmm; | 212 | atomic_long_t tlb_dropin_fail_fmm; |
215 | atomic_long_t tlb_dropin_fail_no_exception; | 213 | atomic_long_t tlb_dropin_fail_no_exception; |
216 | atomic_long_t tlb_dropin_fail_no_exception_war; | ||
217 | atomic_long_t tfh_stale_on_fault; | 214 | atomic_long_t tfh_stale_on_fault; |
218 | atomic_long_t mmu_invalidate_range; | 215 | atomic_long_t mmu_invalidate_range; |
219 | atomic_long_t mmu_invalidate_page; | 216 | atomic_long_t mmu_invalidate_page; |
220 | atomic_long_t mmu_clear_flush_young; | ||
221 | atomic_long_t flush_tlb; | 217 | atomic_long_t flush_tlb; |
222 | atomic_long_t flush_tlb_gru; | 218 | atomic_long_t flush_tlb_gru; |
223 | atomic_long_t flush_tlb_gru_tgh; | 219 | atomic_long_t flush_tlb_gru_tgh; |
224 | atomic_long_t flush_tlb_gru_zero_asid; | 220 | atomic_long_t flush_tlb_gru_zero_asid; |
225 | 221 | ||
226 | atomic_long_t copy_gpa; | 222 | atomic_long_t copy_gpa; |
223 | atomic_long_t read_gpa; | ||
227 | 224 | ||
228 | atomic_long_t mesq_receive; | 225 | atomic_long_t mesq_receive; |
229 | atomic_long_t mesq_receive_none; | 226 | atomic_long_t mesq_receive_none; |
@@ -235,7 +232,7 @@ struct gru_stats_s { | |||
235 | atomic_long_t mesq_send_qlimit_reached; | 232 | atomic_long_t mesq_send_qlimit_reached; |
236 | atomic_long_t mesq_send_amo_nacked; | 233 | atomic_long_t mesq_send_amo_nacked; |
237 | atomic_long_t mesq_send_put_nacked; | 234 | atomic_long_t mesq_send_put_nacked; |
238 | atomic_long_t mesq_qf_not_full; | 235 | atomic_long_t mesq_page_overflow; |
239 | atomic_long_t mesq_qf_locked; | 236 | atomic_long_t mesq_qf_locked; |
240 | atomic_long_t mesq_qf_noop_not_full; | 237 | atomic_long_t mesq_qf_noop_not_full; |
241 | atomic_long_t mesq_qf_switch_head_failed; | 238 | atomic_long_t mesq_qf_switch_head_failed; |
@@ -245,11 +242,13 @@ struct gru_stats_s { | |||
245 | atomic_long_t mesq_noop_qlimit_reached; | 242 | atomic_long_t mesq_noop_qlimit_reached; |
246 | atomic_long_t mesq_noop_amo_nacked; | 243 | atomic_long_t mesq_noop_amo_nacked; |
247 | atomic_long_t mesq_noop_put_nacked; | 244 | atomic_long_t mesq_noop_put_nacked; |
245 | atomic_long_t mesq_noop_page_overflow; | ||
248 | 246 | ||
249 | }; | 247 | }; |
250 | 248 | ||
251 | enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync, | 249 | enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync, |
252 | cchop_deallocate, tghop_invalidate, mcsop_last}; | 250 | cchop_deallocate, tfhop_write_only, tfhop_write_restart, |
251 | tghop_invalidate, mcsop_last}; | ||
253 | 252 | ||
254 | struct mcs_op_statistic { | 253 | struct mcs_op_statistic { |
255 | atomic_long_t count; | 254 | atomic_long_t count; |
@@ -259,8 +258,8 @@ struct mcs_op_statistic { | |||
259 | 258 | ||
260 | extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; | 259 | extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; |
261 | 260 | ||
262 | #define OPT_DPRINT 1 | 261 | #define OPT_DPRINT 1 |
263 | #define OPT_STATS 2 | 262 | #define OPT_STATS 2 |
264 | 263 | ||
265 | 264 | ||
266 | #define IRQ_GRU 110 /* Starting IRQ number for interrupts */ | 265 | #define IRQ_GRU 110 /* Starting IRQ number for interrupts */ |
@@ -283,7 +282,7 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; | |||
283 | #define gru_dbg(dev, fmt, x...) \ | 282 | #define gru_dbg(dev, fmt, x...) \ |
284 | do { \ | 283 | do { \ |
285 | if (gru_options & OPT_DPRINT) \ | 284 | if (gru_options & OPT_DPRINT) \ |
286 | dev_dbg(dev, "%s: " fmt, __func__, x); \ | 285 | printk(KERN_DEBUG "GRU:%d %s: " fmt, smp_processor_id(), __func__, x);\ |
287 | } while (0) | 286 | } while (0) |
288 | #else | 287 | #else |
289 | #define gru_dbg(x...) | 288 | #define gru_dbg(x...) |
@@ -297,13 +296,7 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; | |||
297 | #define ASID_INC 8 /* number of regions */ | 296 | #define ASID_INC 8 /* number of regions */ |
298 | 297 | ||
299 | /* Generate a GRU asid value from a GRU base asid & a virtual address. */ | 298 | /* Generate a GRU asid value from a GRU base asid & a virtual address. */ |
300 | #if defined CONFIG_IA64 | ||
301 | #define VADDR_HI_BIT 64 | 299 | #define VADDR_HI_BIT 64 |
302 | #elif defined CONFIG_X86_64 | ||
303 | #define VADDR_HI_BIT 48 | ||
304 | #else | ||
305 | #error "Unsupported architecture" | ||
306 | #endif | ||
307 | #define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) | 300 | #define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) |
308 | #define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) | 301 | #define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) |
309 | 302 | ||
@@ -345,6 +338,7 @@ struct gru_vma_data { | |||
345 | long vd_user_options;/* misc user option flags */ | 338 | long vd_user_options;/* misc user option flags */ |
346 | int vd_cbr_au_count; | 339 | int vd_cbr_au_count; |
347 | int vd_dsr_au_count; | 340 | int vd_dsr_au_count; |
341 | unsigned char vd_tlb_preload_count; | ||
348 | }; | 342 | }; |
349 | 343 | ||
350 | /* | 344 | /* |
@@ -360,6 +354,7 @@ struct gru_thread_state { | |||
360 | struct gru_state *ts_gru; /* GRU where the context is | 354 | struct gru_state *ts_gru; /* GRU where the context is |
361 | loaded */ | 355 | loaded */ |
362 | struct gru_mm_struct *ts_gms; /* asid & ioproc struct */ | 356 | struct gru_mm_struct *ts_gms; /* asid & ioproc struct */ |
357 | unsigned char ts_tlb_preload_count; /* TLB preload pages */ | ||
363 | unsigned long ts_cbr_map; /* map of allocated CBRs */ | 358 | unsigned long ts_cbr_map; /* map of allocated CBRs */ |
364 | unsigned long ts_dsr_map; /* map of allocated DATA | 359 | unsigned long ts_dsr_map; /* map of allocated DATA |
365 | resources */ | 360 | resources */ |
@@ -368,6 +363,8 @@ struct gru_thread_state { | |||
368 | long ts_user_options;/* misc user option flags */ | 363 | long ts_user_options;/* misc user option flags */ |
369 | pid_t ts_tgid_owner; /* task that is using the | 364 | pid_t ts_tgid_owner; /* task that is using the |
370 | context - for migration */ | 365 | context - for migration */ |
366 | short ts_user_blade_id;/* user selected blade */ | ||
367 | char ts_user_chiplet_id;/* user selected chiplet */ | ||
371 | unsigned short ts_sizeavail; /* Pagesizes in use */ | 368 | unsigned short ts_sizeavail; /* Pagesizes in use */ |
372 | int ts_tsid; /* thread that owns the | 369 | int ts_tsid; /* thread that owns the |
373 | structure */ | 370 | structure */ |
@@ -384,13 +381,11 @@ struct gru_thread_state { | |||
384 | char ts_blade; /* If >= 0, migrate context if | 381 | char ts_blade; /* If >= 0, migrate context if |
385 | ref from diferent blade */ | 382 | ref from diferent blade */ |
386 | char ts_force_cch_reload; | 383 | char ts_force_cch_reload; |
387 | char ts_force_unload;/* force context to be unloaded | ||
388 | after migration */ | ||
389 | char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each | 384 | char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each |
390 | allocated CB */ | 385 | allocated CB */ |
391 | int ts_data_valid; /* Indicates if ts_gdata has | 386 | int ts_data_valid; /* Indicates if ts_gdata has |
392 | valid data */ | 387 | valid data */ |
393 | struct gts_statistics ustats; /* User statistics */ | 388 | struct gru_gseg_statistics ustats; /* User statistics */ |
394 | unsigned long ts_gdata[0]; /* save area for GRU data (CB, | 389 | unsigned long ts_gdata[0]; /* save area for GRU data (CB, |
395 | DS, CBE) */ | 390 | DS, CBE) */ |
396 | }; | 391 | }; |
@@ -422,6 +417,7 @@ struct gru_state { | |||
422 | gru segments (64) */ | 417 | gru segments (64) */ |
423 | unsigned short gs_gid; /* unique GRU number */ | 418 | unsigned short gs_gid; /* unique GRU number */ |
424 | unsigned short gs_blade_id; /* blade of GRU */ | 419 | unsigned short gs_blade_id; /* blade of GRU */ |
420 | unsigned char gs_chiplet_id; /* blade chiplet of GRU */ | ||
425 | unsigned char gs_tgh_local_shift; /* used to pick TGH for | 421 | unsigned char gs_tgh_local_shift; /* used to pick TGH for |
426 | local flush */ | 422 | local flush */ |
427 | unsigned char gs_tgh_first_remote; /* starting TGH# for | 423 | unsigned char gs_tgh_first_remote; /* starting TGH# for |
@@ -453,6 +449,7 @@ struct gru_state { | |||
453 | in use */ | 449 | in use */ |
454 | struct gru_thread_state *gs_gts[GRU_NUM_CCH]; /* GTS currently using | 450 | struct gru_thread_state *gs_gts[GRU_NUM_CCH]; /* GTS currently using |
455 | the context */ | 451 | the context */ |
452 | int gs_irq[GRU_NUM_TFM]; /* Interrupt irqs */ | ||
456 | }; | 453 | }; |
457 | 454 | ||
458 | /* | 455 | /* |
@@ -619,6 +616,15 @@ static inline int is_kernel_context(struct gru_thread_state *gts) | |||
619 | return !gts->ts_mm; | 616 | return !gts->ts_mm; |
620 | } | 617 | } |
621 | 618 | ||
619 | /* | ||
620 | * The following are for Nehelem-EX. A more general scheme is needed for | ||
621 | * future processors. | ||
622 | */ | ||
623 | #define UV_MAX_INT_CORES 8 | ||
624 | #define uv_cpu_socket_number(p) ((cpu_physical_id(p) >> 5) & 1) | ||
625 | #define uv_cpu_ht_number(p) (cpu_physical_id(p) & 1) | ||
626 | #define uv_cpu_core_number(p) (((cpu_physical_id(p) >> 2) & 4) | \ | ||
627 | ((cpu_physical_id(p) >> 1) & 3)) | ||
622 | /*----------------------------------------------------------------------------- | 628 | /*----------------------------------------------------------------------------- |
623 | * Function prototypes & externs | 629 | * Function prototypes & externs |
624 | */ | 630 | */ |
@@ -633,24 +639,26 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct | |||
633 | *vma, int tsid); | 639 | *vma, int tsid); |
634 | extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct | 640 | extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct |
635 | *vma, int tsid); | 641 | *vma, int tsid); |
636 | extern struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, | 642 | extern struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts); |
637 | int blade); | ||
638 | extern void gru_load_context(struct gru_thread_state *gts); | 643 | extern void gru_load_context(struct gru_thread_state *gts); |
639 | extern void gru_steal_context(struct gru_thread_state *gts, int blade_id); | 644 | extern void gru_steal_context(struct gru_thread_state *gts); |
640 | extern void gru_unload_context(struct gru_thread_state *gts, int savestate); | 645 | extern void gru_unload_context(struct gru_thread_state *gts, int savestate); |
641 | extern int gru_update_cch(struct gru_thread_state *gts, int force_unload); | 646 | extern int gru_update_cch(struct gru_thread_state *gts); |
642 | extern void gts_drop(struct gru_thread_state *gts); | 647 | extern void gts_drop(struct gru_thread_state *gts); |
643 | extern void gru_tgh_flush_init(struct gru_state *gru); | 648 | extern void gru_tgh_flush_init(struct gru_state *gru); |
644 | extern int gru_kservices_init(void); | 649 | extern int gru_kservices_init(void); |
645 | extern void gru_kservices_exit(void); | 650 | extern void gru_kservices_exit(void); |
651 | extern irqreturn_t gru0_intr(int irq, void *dev_id); | ||
652 | extern irqreturn_t gru1_intr(int irq, void *dev_id); | ||
653 | extern irqreturn_t gru_intr_mblade(int irq, void *dev_id); | ||
646 | extern int gru_dump_chiplet_request(unsigned long arg); | 654 | extern int gru_dump_chiplet_request(unsigned long arg); |
647 | extern long gru_get_gseg_statistics(unsigned long arg); | 655 | extern long gru_get_gseg_statistics(unsigned long arg); |
648 | extern irqreturn_t gru_intr(int irq, void *dev_id); | ||
649 | extern int gru_handle_user_call_os(unsigned long address); | 656 | extern int gru_handle_user_call_os(unsigned long address); |
650 | extern int gru_user_flush_tlb(unsigned long arg); | 657 | extern int gru_user_flush_tlb(unsigned long arg); |
651 | extern int gru_user_unload_context(unsigned long arg); | 658 | extern int gru_user_unload_context(unsigned long arg); |
652 | extern int gru_get_exception_detail(unsigned long arg); | 659 | extern int gru_get_exception_detail(unsigned long arg); |
653 | extern int gru_set_context_option(unsigned long address); | 660 | extern int gru_set_context_option(unsigned long address); |
661 | extern void gru_check_context_placement(struct gru_thread_state *gts); | ||
654 | extern int gru_cpu_fault_map_id(void); | 662 | extern int gru_cpu_fault_map_id(void); |
655 | extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); | 663 | extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); |
656 | extern void gru_flush_all_tlb(struct gru_state *gru); | 664 | extern void gru_flush_all_tlb(struct gru_state *gru); |
@@ -658,7 +666,8 @@ extern int gru_proc_init(void); | |||
658 | extern void gru_proc_exit(void); | 666 | extern void gru_proc_exit(void); |
659 | 667 | ||
660 | extern struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | 668 | extern struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, |
661 | int cbr_au_count, int dsr_au_count, int options, int tsid); | 669 | int cbr_au_count, int dsr_au_count, |
670 | unsigned char tlb_preload_count, int options, int tsid); | ||
662 | extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, | 671 | extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, |
663 | int cbr_au_count, char *cbmap); | 672 | int cbr_au_count, char *cbmap); |
664 | extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, | 673 | extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, |
diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c index 1d125091f5e7..240a6d361665 100644 --- a/drivers/misc/sgi-gru/grutlbpurge.c +++ b/drivers/misc/sgi-gru/grutlbpurge.c | |||
@@ -184,8 +184,8 @@ void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, | |||
184 | STAT(flush_tlb_gru_tgh); | 184 | STAT(flush_tlb_gru_tgh); |
185 | asid = GRUASID(asid, start); | 185 | asid = GRUASID(asid, start); |
186 | gru_dbg(grudev, | 186 | gru_dbg(grudev, |
187 | " FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n", | 187 | " FLUSH gruid %d, asid 0x%x, vaddr 0x%lx, vamask 0x%x, num %ld, cbmap 0x%x\n", |
188 | gid, asid, num, asids->mt_ctxbitmap); | 188 | gid, asid, start, grupagesize, num, asids->mt_ctxbitmap); |
189 | tgh = get_lock_tgh_handle(gru); | 189 | tgh = get_lock_tgh_handle(gru); |
190 | tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0, | 190 | tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0, |
191 | num - 1, asids->mt_ctxbitmap); | 191 | num - 1, asids->mt_ctxbitmap); |
@@ -299,6 +299,7 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) | |||
299 | { | 299 | { |
300 | struct gru_mm_struct *gms; | 300 | struct gru_mm_struct *gms; |
301 | struct mmu_notifier *mn; | 301 | struct mmu_notifier *mn; |
302 | int err; | ||
302 | 303 | ||
303 | mn = mmu_find_ops(current->mm, &gru_mmuops); | 304 | mn = mmu_find_ops(current->mm, &gru_mmuops); |
304 | if (mn) { | 305 | if (mn) { |
@@ -307,16 +308,22 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) | |||
307 | } else { | 308 | } else { |
308 | gms = kzalloc(sizeof(*gms), GFP_KERNEL); | 309 | gms = kzalloc(sizeof(*gms), GFP_KERNEL); |
309 | if (gms) { | 310 | if (gms) { |
311 | STAT(gms_alloc); | ||
310 | spin_lock_init(&gms->ms_asid_lock); | 312 | spin_lock_init(&gms->ms_asid_lock); |
311 | gms->ms_notifier.ops = &gru_mmuops; | 313 | gms->ms_notifier.ops = &gru_mmuops; |
312 | atomic_set(&gms->ms_refcnt, 1); | 314 | atomic_set(&gms->ms_refcnt, 1); |
313 | init_waitqueue_head(&gms->ms_wait_queue); | 315 | init_waitqueue_head(&gms->ms_wait_queue); |
314 | __mmu_notifier_register(&gms->ms_notifier, current->mm); | 316 | err = __mmu_notifier_register(&gms->ms_notifier, current->mm); |
317 | if (err) | ||
318 | goto error; | ||
315 | } | 319 | } |
316 | } | 320 | } |
317 | gru_dbg(grudev, "gms %p, refcnt %d\n", gms, | 321 | gru_dbg(grudev, "gms %p, refcnt %d\n", gms, |
318 | atomic_read(&gms->ms_refcnt)); | 322 | atomic_read(&gms->ms_refcnt)); |
319 | return gms; | 323 | return gms; |
324 | error: | ||
325 | kfree(gms); | ||
326 | return ERR_PTR(err); | ||
320 | } | 327 | } |
321 | 328 | ||
322 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) | 329 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) |
@@ -327,6 +334,7 @@ void gru_drop_mmu_notifier(struct gru_mm_struct *gms) | |||
327 | if (!gms->ms_released) | 334 | if (!gms->ms_released) |
328 | mmu_notifier_unregister(&gms->ms_notifier, current->mm); | 335 | mmu_notifier_unregister(&gms->ms_notifier, current->mm); |
329 | kfree(gms); | 336 | kfree(gms); |
337 | STAT(gms_free); | ||
330 | } | 338 | } |
331 | } | 339 | } |
332 | 340 | ||
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 2275126cb334..851b2f25ce0e 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h | |||
@@ -339,6 +339,7 @@ extern short xp_partition_id; | |||
339 | extern u8 xp_region_size; | 339 | extern u8 xp_region_size; |
340 | 340 | ||
341 | extern unsigned long (*xp_pa) (void *); | 341 | extern unsigned long (*xp_pa) (void *); |
342 | extern unsigned long (*xp_socket_pa) (unsigned long); | ||
342 | extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, | 343 | extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, |
343 | size_t); | 344 | size_t); |
344 | extern int (*xp_cpu_to_nasid) (int); | 345 | extern int (*xp_cpu_to_nasid) (int); |
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 7896849b16dc..01be66d02ca8 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c | |||
@@ -44,6 +44,9 @@ EXPORT_SYMBOL_GPL(xp_region_size); | |||
44 | unsigned long (*xp_pa) (void *addr); | 44 | unsigned long (*xp_pa) (void *addr); |
45 | EXPORT_SYMBOL_GPL(xp_pa); | 45 | EXPORT_SYMBOL_GPL(xp_pa); |
46 | 46 | ||
47 | unsigned long (*xp_socket_pa) (unsigned long gpa); | ||
48 | EXPORT_SYMBOL_GPL(xp_socket_pa); | ||
49 | |||
47 | enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa, | 50 | enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa, |
48 | const unsigned long src_gpa, size_t len); | 51 | const unsigned long src_gpa, size_t len); |
49 | EXPORT_SYMBOL_GPL(xp_remote_memcpy); | 52 | EXPORT_SYMBOL_GPL(xp_remote_memcpy); |
diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index fb3ec9d735a9..d8e463f87241 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c | |||
@@ -84,6 +84,15 @@ xp_pa_sn2(void *addr) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * Convert a global physical to a socket physical address. | ||
88 | */ | ||
89 | static unsigned long | ||
90 | xp_socket_pa_sn2(unsigned long gpa) | ||
91 | { | ||
92 | return gpa; | ||
93 | } | ||
94 | |||
95 | /* | ||
87 | * Wrapper for bte_copy(). | 96 | * Wrapper for bte_copy(). |
88 | * | 97 | * |
89 | * dst_pa - physical address of the destination of the transfer. | 98 | * dst_pa - physical address of the destination of the transfer. |
@@ -162,6 +171,7 @@ xp_init_sn2(void) | |||
162 | xp_region_size = sn_region_size; | 171 | xp_region_size = sn_region_size; |
163 | 172 | ||
164 | xp_pa = xp_pa_sn2; | 173 | xp_pa = xp_pa_sn2; |
174 | xp_socket_pa = xp_socket_pa_sn2; | ||
165 | xp_remote_memcpy = xp_remote_memcpy_sn2; | 175 | xp_remote_memcpy = xp_remote_memcpy_sn2; |
166 | xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; | 176 | xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; |
167 | xp_expand_memprotect = xp_expand_memprotect_sn2; | 177 | xp_expand_memprotect = xp_expand_memprotect_sn2; |
diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index d238576b26fa..a0d093274dc0 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c | |||
@@ -32,12 +32,44 @@ xp_pa_uv(void *addr) | |||
32 | return uv_gpa(addr); | 32 | return uv_gpa(addr); |
33 | } | 33 | } |
34 | 34 | ||
35 | /* | ||
36 | * Convert a global physical to socket physical address. | ||
37 | */ | ||
38 | static unsigned long | ||
39 | xp_socket_pa_uv(unsigned long gpa) | ||
40 | { | ||
41 | return uv_gpa_to_soc_phys_ram(gpa); | ||
42 | } | ||
43 | |||
44 | static enum xp_retval | ||
45 | xp_remote_mmr_read(unsigned long dst_gpa, const unsigned long src_gpa, | ||
46 | size_t len) | ||
47 | { | ||
48 | int ret; | ||
49 | unsigned long *dst_va = __va(uv_gpa_to_soc_phys_ram(dst_gpa)); | ||
50 | |||
51 | BUG_ON(!uv_gpa_in_mmr_space(src_gpa)); | ||
52 | BUG_ON(len != 8); | ||
53 | |||
54 | ret = gru_read_gpa(dst_va, src_gpa); | ||
55 | if (ret == 0) | ||
56 | return xpSuccess; | ||
57 | |||
58 | dev_err(xp, "gru_read_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx " | ||
59 | "len=%ld\n", dst_gpa, src_gpa, len); | ||
60 | return xpGruCopyError; | ||
61 | } | ||
62 | |||
63 | |||
35 | static enum xp_retval | 64 | static enum xp_retval |
36 | xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, | 65 | xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, |
37 | size_t len) | 66 | size_t len) |
38 | { | 67 | { |
39 | int ret; | 68 | int ret; |
40 | 69 | ||
70 | if (uv_gpa_in_mmr_space(src_gpa)) | ||
71 | return xp_remote_mmr_read(dst_gpa, src_gpa, len); | ||
72 | |||
41 | ret = gru_copy_gpa(dst_gpa, src_gpa, len); | 73 | ret = gru_copy_gpa(dst_gpa, src_gpa, len); |
42 | if (ret == 0) | 74 | if (ret == 0) |
43 | return xpSuccess; | 75 | return xpSuccess; |
@@ -123,6 +155,7 @@ xp_init_uv(void) | |||
123 | xp_region_size = sn_region_size; | 155 | xp_region_size = sn_region_size; |
124 | 156 | ||
125 | xp_pa = xp_pa_uv; | 157 | xp_pa = xp_pa_uv; |
158 | xp_socket_pa = xp_socket_pa_uv; | ||
126 | xp_remote_memcpy = xp_remote_memcpy_uv; | 159 | xp_remote_memcpy = xp_remote_memcpy_uv; |
127 | xp_cpu_to_nasid = xp_cpu_to_nasid_uv; | 160 | xp_cpu_to_nasid = xp_cpu_to_nasid_uv; |
128 | xp_expand_memprotect = xp_expand_memprotect_uv; | 161 | xp_expand_memprotect = xp_expand_memprotect_uv; |
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 65877bc5edaa..9a6268c89fdd 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/hardirq.h> | 19 | #include <linux/hardirq.h> |
20 | #include "xpc.h" | 20 | #include "xpc.h" |
21 | #include <asm/uv/uv_hub.h> | ||
21 | 22 | ||
22 | /* XPC is exiting flag */ | 23 | /* XPC is exiting flag */ |
23 | int xpc_exiting; | 24 | int xpc_exiting; |
@@ -92,8 +93,12 @@ xpc_get_rsvd_page_pa(int nasid) | |||
92 | break; | 93 | break; |
93 | 94 | ||
94 | /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ | 95 | /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ |
95 | if (L1_CACHE_ALIGN(len) > buf_len) { | 96 | if (is_shub()) |
96 | kfree(buf_base); | 97 | len = L1_CACHE_ALIGN(len); |
98 | |||
99 | if (len > buf_len) { | ||
100 | if (buf_base != NULL) | ||
101 | kfree(buf_base); | ||
97 | buf_len = L1_CACHE_ALIGN(len); | 102 | buf_len = L1_CACHE_ALIGN(len); |
98 | buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, | 103 | buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, |
99 | &buf_base); | 104 | &buf_base); |
@@ -105,7 +110,7 @@ xpc_get_rsvd_page_pa(int nasid) | |||
105 | } | 110 | } |
106 | } | 111 | } |
107 | 112 | ||
108 | ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len); | 113 | ret = xp_remote_memcpy(xp_pa(buf), rp_pa, len); |
109 | if (ret != xpSuccess) { | 114 | if (ret != xpSuccess) { |
110 | dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); | 115 | dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); |
111 | break; | 116 | break; |
@@ -143,7 +148,7 @@ xpc_setup_rsvd_page(void) | |||
143 | dev_err(xpc_part, "SAL failed to locate the reserved page\n"); | 148 | dev_err(xpc_part, "SAL failed to locate the reserved page\n"); |
144 | return -ESRCH; | 149 | return -ESRCH; |
145 | } | 150 | } |
146 | rp = (struct xpc_rsvd_page *)__va(rp_pa); | 151 | rp = (struct xpc_rsvd_page *)__va(xp_socket_pa(rp_pa)); |
147 | 152 | ||
148 | if (rp->SAL_version < 3) { | 153 | if (rp->SAL_version < 3) { |
149 | /* SAL_versions < 3 had a SAL_partid defined as a u8 */ | 154 | /* SAL_versions < 3 had a SAL_partid defined as a u8 */ |
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index b5bbe59f9c57..8725d5e8ab0c 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c | |||
@@ -157,22 +157,24 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq) | |||
157 | { | 157 | { |
158 | int ret; | 158 | int ret; |
159 | 159 | ||
160 | #if defined CONFIG_X86_64 | 160 | #if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV |
161 | ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), | 161 | int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); |
162 | mq->order, &mq->mmr_offset); | 162 | |
163 | if (ret < 0) { | 163 | ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address), |
164 | dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " | ||
165 | "ret=%d\n", ret); | ||
166 | return ret; | ||
167 | } | ||
168 | #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV | ||
169 | ret = sn_mq_watchlist_alloc(mq->mmr_blade, (void *)uv_gpa(mq->address), | ||
170 | mq->order, &mq->mmr_offset); | 164 | mq->order, &mq->mmr_offset); |
171 | if (ret < 0) { | 165 | if (ret < 0) { |
172 | dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", | 166 | dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", |
173 | ret); | 167 | ret); |
174 | return -EBUSY; | 168 | return -EBUSY; |
175 | } | 169 | } |
170 | #elif defined CONFIG_X86_64 | ||
171 | ret = uv_bios_mq_watchlist_alloc(uv_gpa(mq->address), | ||
172 | mq->order, &mq->mmr_offset); | ||
173 | if (ret < 0) { | ||
174 | dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " | ||
175 | "ret=%d\n", ret); | ||
176 | return ret; | ||
177 | } | ||
176 | #else | 178 | #else |
177 | #error not a supported configuration | 179 | #error not a supported configuration |
178 | #endif | 180 | #endif |
@@ -185,12 +187,13 @@ static void | |||
185 | xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq) | 187 | xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq) |
186 | { | 188 | { |
187 | int ret; | 189 | int ret; |
190 | int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); | ||
188 | 191 | ||
189 | #if defined CONFIG_X86_64 | 192 | #if defined CONFIG_X86_64 |
190 | ret = uv_bios_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); | 193 | ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num); |
191 | BUG_ON(ret != BIOS_STATUS_SUCCESS); | 194 | BUG_ON(ret != BIOS_STATUS_SUCCESS); |
192 | #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV | 195 | #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV |
193 | ret = sn_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); | 196 | ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num); |
194 | BUG_ON(ret != SALRET_OK); | 197 | BUG_ON(ret != SALRET_OK); |
195 | #else | 198 | #else |
196 | #error not a supported configuration | 199 | #error not a supported configuration |
@@ -204,6 +207,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, | |||
204 | enum xp_retval xp_ret; | 207 | enum xp_retval xp_ret; |
205 | int ret; | 208 | int ret; |
206 | int nid; | 209 | int nid; |
210 | int nasid; | ||
207 | int pg_order; | 211 | int pg_order; |
208 | struct page *page; | 212 | struct page *page; |
209 | struct xpc_gru_mq_uv *mq; | 213 | struct xpc_gru_mq_uv *mq; |
@@ -259,9 +263,11 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, | |||
259 | goto out_5; | 263 | goto out_5; |
260 | } | 264 | } |
261 | 265 | ||
266 | nasid = UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpu)); | ||
267 | |||
262 | mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value; | 268 | mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value; |
263 | ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size, | 269 | ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size, |
264 | nid, mmr_value->vector, mmr_value->dest); | 270 | nasid, mmr_value->vector, mmr_value->dest); |
265 | if (ret != 0) { | 271 | if (ret != 0) { |
266 | dev_err(xpc_part, "gru_create_message_queue() returned " | 272 | dev_err(xpc_part, "gru_create_message_queue() returned " |
267 | "error=%d\n", ret); | 273 | "error=%d\n", ret); |
@@ -946,11 +952,13 @@ xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head) | |||
946 | head->first = first->next; | 952 | head->first = first->next; |
947 | if (head->first == NULL) | 953 | if (head->first == NULL) |
948 | head->last = NULL; | 954 | head->last = NULL; |
955 | |||
956 | head->n_entries--; | ||
957 | BUG_ON(head->n_entries < 0); | ||
958 | |||
959 | first->next = NULL; | ||
949 | } | 960 | } |
950 | head->n_entries--; | ||
951 | BUG_ON(head->n_entries < 0); | ||
952 | spin_unlock_irqrestore(&head->lock, irq_flags); | 961 | spin_unlock_irqrestore(&head->lock, irq_flags); |
953 | first->next = NULL; | ||
954 | return first; | 962 | return first; |
955 | } | 963 | } |
956 | 964 | ||
@@ -1019,7 +1027,8 @@ xpc_make_first_contact_uv(struct xpc_partition *part) | |||
1019 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), | 1027 | xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), |
1020 | XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); | 1028 | XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); |
1021 | 1029 | ||
1022 | while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) { | 1030 | while (!((part->sn.uv.remote_act_state == XPC_P_AS_ACTIVATING) || |
1031 | (part->sn.uv.remote_act_state == XPC_P_AS_ACTIVE))) { | ||
1023 | 1032 | ||
1024 | dev_dbg(xpc_part, "waiting to make first contact with " | 1033 | dev_dbg(xpc_part, "waiting to make first contact with " |
1025 | "partition %d\n", XPC_PARTID(part)); | 1034 | "partition %d\n", XPC_PARTID(part)); |
@@ -1422,7 +1431,6 @@ xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, | |||
1422 | msg_slot = ch_uv->recv_msg_slots + | 1431 | msg_slot = ch_uv->recv_msg_slots + |
1423 | (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size; | 1432 | (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size; |
1424 | 1433 | ||
1425 | BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number); | ||
1426 | BUG_ON(msg_slot->hdr.size != 0); | 1434 | BUG_ON(msg_slot->hdr.size != 0); |
1427 | 1435 | ||
1428 | memcpy(msg_slot, msg, msg->hdr.size); | 1436 | memcpy(msg_slot, msg, msg->hdr.size); |
@@ -1646,8 +1654,6 @@ xpc_received_payload_uv(struct xpc_channel *ch, void *payload) | |||
1646 | sizeof(struct xpc_notify_mq_msghdr_uv)); | 1654 | sizeof(struct xpc_notify_mq_msghdr_uv)); |
1647 | if (ret != xpSuccess) | 1655 | if (ret != xpSuccess) |
1648 | XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); | 1656 | XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); |
1649 | |||
1650 | msg->hdr.msg_slot_number += ch->remote_nentries; | ||
1651 | } | 1657 | } |
1652 | 1658 | ||
1653 | static struct xpc_arch_operations xpc_arch_ops_uv = { | 1659 | static struct xpc_arch_operations xpc_arch_ops_uv = { |
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index ad95d5f7b630..8c8515619b8e 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c | |||
@@ -72,35 +72,6 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) | |||
72 | mlx4_bitmap_free_range(bitmap, obj, 1); | 72 | mlx4_bitmap_free_range(bitmap, obj, 1); |
73 | } | 73 | } |
74 | 74 | ||
75 | static unsigned long find_aligned_range(unsigned long *bitmap, | ||
76 | u32 start, u32 nbits, | ||
77 | int len, int align) | ||
78 | { | ||
79 | unsigned long end, i; | ||
80 | |||
81 | again: | ||
82 | start = ALIGN(start, align); | ||
83 | |||
84 | while ((start < nbits) && test_bit(start, bitmap)) | ||
85 | start += align; | ||
86 | |||
87 | if (start >= nbits) | ||
88 | return -1; | ||
89 | |||
90 | end = start+len; | ||
91 | if (end > nbits) | ||
92 | return -1; | ||
93 | |||
94 | for (i = start + 1; i < end; i++) { | ||
95 | if (test_bit(i, bitmap)) { | ||
96 | start = i + 1; | ||
97 | goto again; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | return start; | ||
102 | } | ||
103 | |||
104 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | 75 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) |
105 | { | 76 | { |
106 | u32 obj, i; | 77 | u32 obj, i; |
@@ -110,13 +81,13 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | |||
110 | 81 | ||
111 | spin_lock(&bitmap->lock); | 82 | spin_lock(&bitmap->lock); |
112 | 83 | ||
113 | obj = find_aligned_range(bitmap->table, bitmap->last, | 84 | obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, |
114 | bitmap->max, cnt, align); | 85 | bitmap->last, cnt, align - 1); |
115 | if (obj >= bitmap->max) { | 86 | if (obj >= bitmap->max) { |
116 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) | 87 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) |
117 | & bitmap->mask; | 88 | & bitmap->mask; |
118 | obj = find_aligned_range(bitmap->table, 0, bitmap->max, | 89 | obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, |
119 | cnt, align); | 90 | 0, cnt, align - 1); |
120 | } | 91 | } |
121 | 92 | ||
122 | if (obj < bitmap->max) { | 93 | if (obj < bitmap->max) { |
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 2597145a066e..ad113b0f62db 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c | |||
@@ -3403,7 +3403,7 @@ static int __init parport_parse_param(const char *s, int *val, | |||
3403 | *val = automatic; | 3403 | *val = automatic; |
3404 | else if (!strncmp(s, "none", 4)) | 3404 | else if (!strncmp(s, "none", 4)) |
3405 | *val = none; | 3405 | *val = none; |
3406 | else if (nofifo && !strncmp(s, "nofifo", 4)) | 3406 | else if (nofifo && !strncmp(s, "nofifo", 6)) |
3407 | *val = nofifo; | 3407 | *val = nofifo; |
3408 | else { | 3408 | else { |
3409 | char *ep; | 3409 | char *ep; |
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 6cdc931f7c17..83aae4747594 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -339,6 +339,35 @@ found: | |||
339 | } | 339 | } |
340 | #endif | 340 | #endif |
341 | 341 | ||
342 | #ifdef CONFIG_ACPI_NUMA | ||
343 | static int __init | ||
344 | dmar_parse_one_rhsa(struct acpi_dmar_header *header) | ||
345 | { | ||
346 | struct acpi_dmar_rhsa *rhsa; | ||
347 | struct dmar_drhd_unit *drhd; | ||
348 | |||
349 | rhsa = (struct acpi_dmar_rhsa *)header; | ||
350 | for_each_drhd_unit(drhd) { | ||
351 | if (drhd->reg_base_addr == rhsa->base_address) { | ||
352 | int node = acpi_map_pxm_to_node(rhsa->proximity_domain); | ||
353 | |||
354 | if (!node_online(node)) | ||
355 | node = -1; | ||
356 | drhd->iommu->node = node; | ||
357 | return 0; | ||
358 | } | ||
359 | } | ||
360 | WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n" | ||
361 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
362 | drhd->reg_base_addr, | ||
363 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
364 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
365 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | #endif | ||
370 | |||
342 | static void __init | 371 | static void __init |
343 | dmar_table_print_dmar_entry(struct acpi_dmar_header *header) | 372 | dmar_table_print_dmar_entry(struct acpi_dmar_header *header) |
344 | { | 373 | { |
@@ -458,7 +487,9 @@ parse_dmar_table(void) | |||
458 | #endif | 487 | #endif |
459 | break; | 488 | break; |
460 | case ACPI_DMAR_HARDWARE_AFFINITY: | 489 | case ACPI_DMAR_HARDWARE_AFFINITY: |
461 | /* We don't do anything with RHSA (yet?) */ | 490 | #ifdef CONFIG_ACPI_NUMA |
491 | ret = dmar_parse_one_rhsa(entry_header); | ||
492 | #endif | ||
462 | break; | 493 | break; |
463 | default: | 494 | default: |
464 | printk(KERN_WARNING PREFIX | 495 | printk(KERN_WARNING PREFIX |
@@ -582,6 +613,8 @@ int __init dmar_table_init(void) | |||
582 | return 0; | 613 | return 0; |
583 | } | 614 | } |
584 | 615 | ||
616 | static int bios_warned; | ||
617 | |||
585 | int __init check_zero_address(void) | 618 | int __init check_zero_address(void) |
586 | { | 619 | { |
587 | struct acpi_table_dmar *dmar; | 620 | struct acpi_table_dmar *dmar; |
@@ -601,6 +634,9 @@ int __init check_zero_address(void) | |||
601 | } | 634 | } |
602 | 635 | ||
603 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { | 636 | if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { |
637 | void __iomem *addr; | ||
638 | u64 cap, ecap; | ||
639 | |||
604 | drhd = (void *)entry_header; | 640 | drhd = (void *)entry_header; |
605 | if (!drhd->address) { | 641 | if (!drhd->address) { |
606 | /* Promote an attitude of violence to a BIOS engineer today */ | 642 | /* Promote an attitude of violence to a BIOS engineer today */ |
@@ -609,17 +645,40 @@ int __init check_zero_address(void) | |||
609 | dmi_get_system_info(DMI_BIOS_VENDOR), | 645 | dmi_get_system_info(DMI_BIOS_VENDOR), |
610 | dmi_get_system_info(DMI_BIOS_VERSION), | 646 | dmi_get_system_info(DMI_BIOS_VERSION), |
611 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | 647 | dmi_get_system_info(DMI_PRODUCT_VERSION)); |
612 | #ifdef CONFIG_DMAR | 648 | bios_warned = 1; |
613 | dmar_disabled = 1; | 649 | goto failed; |
614 | #endif | 650 | } |
615 | return 0; | 651 | |
652 | addr = early_ioremap(drhd->address, VTD_PAGE_SIZE); | ||
653 | if (!addr ) { | ||
654 | printk("IOMMU: can't validate: %llx\n", drhd->address); | ||
655 | goto failed; | ||
656 | } | ||
657 | cap = dmar_readq(addr + DMAR_CAP_REG); | ||
658 | ecap = dmar_readq(addr + DMAR_ECAP_REG); | ||
659 | early_iounmap(addr, VTD_PAGE_SIZE); | ||
660 | if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) { | ||
661 | /* Promote an attitude of violence to a BIOS engineer today */ | ||
662 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" | ||
663 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
664 | drhd->address, | ||
665 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
666 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
667 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
668 | bios_warned = 1; | ||
669 | goto failed; | ||
616 | } | 670 | } |
617 | break; | ||
618 | } | 671 | } |
619 | 672 | ||
620 | entry_header = ((void *)entry_header + entry_header->length); | 673 | entry_header = ((void *)entry_header + entry_header->length); |
621 | } | 674 | } |
622 | return 1; | 675 | return 1; |
676 | |||
677 | failed: | ||
678 | #ifdef CONFIG_DMAR | ||
679 | dmar_disabled = 1; | ||
680 | #endif | ||
681 | return 0; | ||
623 | } | 682 | } |
624 | 683 | ||
625 | void __init detect_intel_iommu(void) | 684 | void __init detect_intel_iommu(void) |
@@ -670,6 +729,18 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
670 | int agaw = 0; | 729 | int agaw = 0; |
671 | int msagaw = 0; | 730 | int msagaw = 0; |
672 | 731 | ||
732 | if (!drhd->reg_base_addr) { | ||
733 | if (!bios_warned) { | ||
734 | WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" | ||
735 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
736 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
737 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
738 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
739 | bios_warned = 1; | ||
740 | } | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | |||
673 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 744 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
674 | if (!iommu) | 745 | if (!iommu) |
675 | return -ENOMEM; | 746 | return -ENOMEM; |
@@ -686,13 +757,16 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
686 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); | 757 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); |
687 | 758 | ||
688 | if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { | 759 | if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { |
689 | /* Promote an attitude of violence to a BIOS engineer today */ | 760 | if (!bios_warned) { |
690 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" | 761 | /* Promote an attitude of violence to a BIOS engineer today */ |
691 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | 762 | WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" |
692 | drhd->reg_base_addr, | 763 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", |
693 | dmi_get_system_info(DMI_BIOS_VENDOR), | 764 | drhd->reg_base_addr, |
694 | dmi_get_system_info(DMI_BIOS_VERSION), | 765 | dmi_get_system_info(DMI_BIOS_VENDOR), |
695 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | 766 | dmi_get_system_info(DMI_BIOS_VERSION), |
767 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
768 | bios_warned = 1; | ||
769 | } | ||
696 | goto err_unmap; | 770 | goto err_unmap; |
697 | } | 771 | } |
698 | 772 | ||
@@ -715,6 +789,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
715 | iommu->agaw = agaw; | 789 | iommu->agaw = agaw; |
716 | iommu->msagaw = msagaw; | 790 | iommu->msagaw = msagaw; |
717 | 791 | ||
792 | iommu->node = -1; | ||
793 | |||
718 | /* the registers might be more than one page */ | 794 | /* the registers might be more than one page */ |
719 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), | 795 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), |
720 | cap_max_fault_reg_offset(iommu->cap)); | 796 | cap_max_fault_reg_offset(iommu->cap)); |
@@ -1056,6 +1132,7 @@ static void __dmar_enable_qi(struct intel_iommu *iommu) | |||
1056 | int dmar_enable_qi(struct intel_iommu *iommu) | 1132 | int dmar_enable_qi(struct intel_iommu *iommu) |
1057 | { | 1133 | { |
1058 | struct q_inval *qi; | 1134 | struct q_inval *qi; |
1135 | struct page *desc_page; | ||
1059 | 1136 | ||
1060 | if (!ecap_qis(iommu->ecap)) | 1137 | if (!ecap_qis(iommu->ecap)) |
1061 | return -ENOENT; | 1138 | return -ENOENT; |
@@ -1072,13 +1149,16 @@ int dmar_enable_qi(struct intel_iommu *iommu) | |||
1072 | 1149 | ||
1073 | qi = iommu->qi; | 1150 | qi = iommu->qi; |
1074 | 1151 | ||
1075 | qi->desc = (void *)(get_zeroed_page(GFP_ATOMIC)); | 1152 | |
1076 | if (!qi->desc) { | 1153 | desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); |
1154 | if (!desc_page) { | ||
1077 | kfree(qi); | 1155 | kfree(qi); |
1078 | iommu->qi = 0; | 1156 | iommu->qi = 0; |
1079 | return -ENOMEM; | 1157 | return -ENOMEM; |
1080 | } | 1158 | } |
1081 | 1159 | ||
1160 | qi->desc = page_address(desc_page); | ||
1161 | |||
1082 | qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); | 1162 | qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); |
1083 | if (!qi->desc_status) { | 1163 | if (!qi->desc_status) { |
1084 | free_page((unsigned long) qi->desc); | 1164 | free_page((unsigned long) qi->desc); |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 8d6159426311..e56f9bed6f2b 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -277,6 +277,7 @@ static int hw_pass_through = 1; | |||
277 | 277 | ||
278 | struct dmar_domain { | 278 | struct dmar_domain { |
279 | int id; /* domain id */ | 279 | int id; /* domain id */ |
280 | int nid; /* node id */ | ||
280 | unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/ | 281 | unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/ |
281 | 282 | ||
282 | struct list_head devices; /* all devices' list */ | 283 | struct list_head devices; /* all devices' list */ |
@@ -386,30 +387,14 @@ static struct kmem_cache *iommu_domain_cache; | |||
386 | static struct kmem_cache *iommu_devinfo_cache; | 387 | static struct kmem_cache *iommu_devinfo_cache; |
387 | static struct kmem_cache *iommu_iova_cache; | 388 | static struct kmem_cache *iommu_iova_cache; |
388 | 389 | ||
389 | static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep) | 390 | static inline void *alloc_pgtable_page(int node) |
390 | { | 391 | { |
391 | unsigned int flags; | 392 | struct page *page; |
392 | void *vaddr; | 393 | void *vaddr = NULL; |
393 | |||
394 | /* trying to avoid low memory issues */ | ||
395 | flags = current->flags & PF_MEMALLOC; | ||
396 | current->flags |= PF_MEMALLOC; | ||
397 | vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC); | ||
398 | current->flags &= (~PF_MEMALLOC | flags); | ||
399 | return vaddr; | ||
400 | } | ||
401 | |||
402 | 394 | ||
403 | static inline void *alloc_pgtable_page(void) | 395 | page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); |
404 | { | 396 | if (page) |
405 | unsigned int flags; | 397 | vaddr = page_address(page); |
406 | void *vaddr; | ||
407 | |||
408 | /* trying to avoid low memory issues */ | ||
409 | flags = current->flags & PF_MEMALLOC; | ||
410 | current->flags |= PF_MEMALLOC; | ||
411 | vaddr = (void *)get_zeroed_page(GFP_ATOMIC); | ||
412 | current->flags &= (~PF_MEMALLOC | flags); | ||
413 | return vaddr; | 398 | return vaddr; |
414 | } | 399 | } |
415 | 400 | ||
@@ -420,7 +405,7 @@ static inline void free_pgtable_page(void *vaddr) | |||
420 | 405 | ||
421 | static inline void *alloc_domain_mem(void) | 406 | static inline void *alloc_domain_mem(void) |
422 | { | 407 | { |
423 | return iommu_kmem_cache_alloc(iommu_domain_cache); | 408 | return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC); |
424 | } | 409 | } |
425 | 410 | ||
426 | static void free_domain_mem(void *vaddr) | 411 | static void free_domain_mem(void *vaddr) |
@@ -430,7 +415,7 @@ static void free_domain_mem(void *vaddr) | |||
430 | 415 | ||
431 | static inline void * alloc_devinfo_mem(void) | 416 | static inline void * alloc_devinfo_mem(void) |
432 | { | 417 | { |
433 | return iommu_kmem_cache_alloc(iommu_devinfo_cache); | 418 | return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC); |
434 | } | 419 | } |
435 | 420 | ||
436 | static inline void free_devinfo_mem(void *vaddr) | 421 | static inline void free_devinfo_mem(void *vaddr) |
@@ -440,7 +425,7 @@ static inline void free_devinfo_mem(void *vaddr) | |||
440 | 425 | ||
441 | struct iova *alloc_iova_mem(void) | 426 | struct iova *alloc_iova_mem(void) |
442 | { | 427 | { |
443 | return iommu_kmem_cache_alloc(iommu_iova_cache); | 428 | return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC); |
444 | } | 429 | } |
445 | 430 | ||
446 | void free_iova_mem(struct iova *iova) | 431 | void free_iova_mem(struct iova *iova) |
@@ -589,7 +574,8 @@ static struct context_entry * device_to_context_entry(struct intel_iommu *iommu, | |||
589 | root = &iommu->root_entry[bus]; | 574 | root = &iommu->root_entry[bus]; |
590 | context = get_context_addr_from_root(root); | 575 | context = get_context_addr_from_root(root); |
591 | if (!context) { | 576 | if (!context) { |
592 | context = (struct context_entry *)alloc_pgtable_page(); | 577 | context = (struct context_entry *) |
578 | alloc_pgtable_page(iommu->node); | ||
593 | if (!context) { | 579 | if (!context) { |
594 | spin_unlock_irqrestore(&iommu->lock, flags); | 580 | spin_unlock_irqrestore(&iommu->lock, flags); |
595 | return NULL; | 581 | return NULL; |
@@ -732,7 +718,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, | |||
732 | if (!dma_pte_present(pte)) { | 718 | if (!dma_pte_present(pte)) { |
733 | uint64_t pteval; | 719 | uint64_t pteval; |
734 | 720 | ||
735 | tmp_page = alloc_pgtable_page(); | 721 | tmp_page = alloc_pgtable_page(domain->nid); |
736 | 722 | ||
737 | if (!tmp_page) | 723 | if (!tmp_page) |
738 | return NULL; | 724 | return NULL; |
@@ -868,7 +854,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu) | |||
868 | struct root_entry *root; | 854 | struct root_entry *root; |
869 | unsigned long flags; | 855 | unsigned long flags; |
870 | 856 | ||
871 | root = (struct root_entry *)alloc_pgtable_page(); | 857 | root = (struct root_entry *)alloc_pgtable_page(iommu->node); |
872 | if (!root) | 858 | if (!root) |
873 | return -ENOMEM; | 859 | return -ENOMEM; |
874 | 860 | ||
@@ -1263,6 +1249,7 @@ static struct dmar_domain *alloc_domain(void) | |||
1263 | if (!domain) | 1249 | if (!domain) |
1264 | return NULL; | 1250 | return NULL; |
1265 | 1251 | ||
1252 | domain->nid = -1; | ||
1266 | memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); | 1253 | memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); |
1267 | domain->flags = 0; | 1254 | domain->flags = 0; |
1268 | 1255 | ||
@@ -1420,9 +1407,10 @@ static int domain_init(struct dmar_domain *domain, int guest_width) | |||
1420 | domain->iommu_snooping = 0; | 1407 | domain->iommu_snooping = 0; |
1421 | 1408 | ||
1422 | domain->iommu_count = 1; | 1409 | domain->iommu_count = 1; |
1410 | domain->nid = iommu->node; | ||
1423 | 1411 | ||
1424 | /* always allocate the top pgd */ | 1412 | /* always allocate the top pgd */ |
1425 | domain->pgd = (struct dma_pte *)alloc_pgtable_page(); | 1413 | domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); |
1426 | if (!domain->pgd) | 1414 | if (!domain->pgd) |
1427 | return -ENOMEM; | 1415 | return -ENOMEM; |
1428 | __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE); | 1416 | __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE); |
@@ -1523,12 +1511,15 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, | |||
1523 | 1511 | ||
1524 | /* Skip top levels of page tables for | 1512 | /* Skip top levels of page tables for |
1525 | * iommu which has less agaw than default. | 1513 | * iommu which has less agaw than default. |
1514 | * Unnecessary for PT mode. | ||
1526 | */ | 1515 | */ |
1527 | for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { | 1516 | if (translation != CONTEXT_TT_PASS_THROUGH) { |
1528 | pgd = phys_to_virt(dma_pte_addr(pgd)); | 1517 | for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { |
1529 | if (!dma_pte_present(pgd)) { | 1518 | pgd = phys_to_virt(dma_pte_addr(pgd)); |
1530 | spin_unlock_irqrestore(&iommu->lock, flags); | 1519 | if (!dma_pte_present(pgd)) { |
1531 | return -ENOMEM; | 1520 | spin_unlock_irqrestore(&iommu->lock, flags); |
1521 | return -ENOMEM; | ||
1522 | } | ||
1532 | } | 1523 | } |
1533 | } | 1524 | } |
1534 | } | 1525 | } |
@@ -1577,6 +1568,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, | |||
1577 | spin_lock_irqsave(&domain->iommu_lock, flags); | 1568 | spin_lock_irqsave(&domain->iommu_lock, flags); |
1578 | if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) { | 1569 | if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) { |
1579 | domain->iommu_count++; | 1570 | domain->iommu_count++; |
1571 | if (domain->iommu_count == 1) | ||
1572 | domain->nid = iommu->node; | ||
1580 | domain_update_iommu_cap(domain); | 1573 | domain_update_iommu_cap(domain); |
1581 | } | 1574 | } |
1582 | spin_unlock_irqrestore(&domain->iommu_lock, flags); | 1575 | spin_unlock_irqrestore(&domain->iommu_lock, flags); |
@@ -1991,6 +1984,16 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, | |||
1991 | "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", | 1984 | "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", |
1992 | pci_name(pdev), start, end); | 1985 | pci_name(pdev), start, end); |
1993 | 1986 | ||
1987 | if (end < start) { | ||
1988 | WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n" | ||
1989 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | ||
1990 | dmi_get_system_info(DMI_BIOS_VENDOR), | ||
1991 | dmi_get_system_info(DMI_BIOS_VERSION), | ||
1992 | dmi_get_system_info(DMI_PRODUCT_VERSION)); | ||
1993 | ret = -EIO; | ||
1994 | goto error; | ||
1995 | } | ||
1996 | |||
1994 | if (end >> agaw_to_width(domain->agaw)) { | 1997 | if (end >> agaw_to_width(domain->agaw)) { |
1995 | WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n" | 1998 | WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n" |
1996 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", | 1999 | "BIOS vendor: %s; Ver: %s; Product Version: %s\n", |
@@ -3228,6 +3231,9 @@ static int device_notifier(struct notifier_block *nb, | |||
3228 | struct pci_dev *pdev = to_pci_dev(dev); | 3231 | struct pci_dev *pdev = to_pci_dev(dev); |
3229 | struct dmar_domain *domain; | 3232 | struct dmar_domain *domain; |
3230 | 3233 | ||
3234 | if (iommu_no_mapping(dev)) | ||
3235 | return 0; | ||
3236 | |||
3231 | domain = find_domain(pdev); | 3237 | domain = find_domain(pdev); |
3232 | if (!domain) | 3238 | if (!domain) |
3233 | return 0; | 3239 | return 0; |
@@ -3455,6 +3461,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void) | |||
3455 | return NULL; | 3461 | return NULL; |
3456 | 3462 | ||
3457 | domain->id = vm_domid++; | 3463 | domain->id = vm_domid++; |
3464 | domain->nid = -1; | ||
3458 | memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); | 3465 | memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); |
3459 | domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE; | 3466 | domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE; |
3460 | 3467 | ||
@@ -3481,9 +3488,10 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) | |||
3481 | domain->iommu_coherency = 0; | 3488 | domain->iommu_coherency = 0; |
3482 | domain->iommu_snooping = 0; | 3489 | domain->iommu_snooping = 0; |
3483 | domain->max_addr = 0; | 3490 | domain->max_addr = 0; |
3491 | domain->nid = -1; | ||
3484 | 3492 | ||
3485 | /* always allocate the top pgd */ | 3493 | /* always allocate the top pgd */ |
3486 | domain->pgd = (struct dma_pte *)alloc_pgtable_page(); | 3494 | domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); |
3487 | if (!domain->pgd) | 3495 | if (!domain->pgd) |
3488 | return -ENOMEM; | 3496 | return -ENOMEM; |
3489 | domain_flush_cache(domain, domain->pgd, PAGE_SIZE); | 3497 | domain_flush_cache(domain, domain->pgd, PAGE_SIZE); |
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 1487bf2be863..8b65a489581b 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -590,7 +590,8 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode) | |||
590 | if (!iommu->ir_table) | 590 | if (!iommu->ir_table) |
591 | return -ENOMEM; | 591 | return -ENOMEM; |
592 | 592 | ||
593 | pages = alloc_pages(GFP_ATOMIC | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); | 593 | pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, |
594 | INTR_REMAP_PAGE_ORDER); | ||
594 | 595 | ||
595 | if (!pages) { | 596 | if (!pages) { |
596 | printk(KERN_ERR "failed to allocate pages of order %d\n", | 597 | printk(KERN_ERR "failed to allocate pages of order %d\n", |
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index b35d921bac6e..2d8ac43f78e8 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/proc_fs.h> | 25 | #include <linux/proc_fs.h> |
26 | #include <linux/pnp.h> | 26 | #include <linux/pnp.h> |
27 | #include <linux/seq_file.h> | ||
27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
28 | 29 | ||
29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
@@ -33,42 +34,65 @@ | |||
33 | static struct proc_dir_entry *proc_pnp = NULL; | 34 | static struct proc_dir_entry *proc_pnp = NULL; |
34 | static struct proc_dir_entry *proc_pnp_boot = NULL; | 35 | static struct proc_dir_entry *proc_pnp_boot = NULL; |
35 | 36 | ||
36 | static int proc_read_pnpconfig(char *buf, char **start, off_t pos, | 37 | static int pnpconfig_proc_show(struct seq_file *m, void *v) |
37 | int count, int *eof, void *data) | ||
38 | { | 38 | { |
39 | struct pnp_isa_config_struc pnps; | 39 | struct pnp_isa_config_struc pnps; |
40 | 40 | ||
41 | if (pnp_bios_isapnp_config(&pnps)) | 41 | if (pnp_bios_isapnp_config(&pnps)) |
42 | return -EIO; | 42 | return -EIO; |
43 | return snprintf(buf, count, | 43 | seq_printf(m, "structure_revision %d\n" |
44 | "structure_revision %d\n" | 44 | "number_of_CSNs %d\n" |
45 | "number_of_CSNs %d\n" | 45 | "ISA_read_data_port 0x%x\n", |
46 | "ISA_read_data_port 0x%x\n", | 46 | pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); |
47 | pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); | 47 | return 0; |
48 | } | 48 | } |
49 | 49 | ||
50 | static int proc_read_escdinfo(char *buf, char **start, off_t pos, | 50 | static int pnpconfig_proc_open(struct inode *inode, struct file *file) |
51 | int count, int *eof, void *data) | 51 | { |
52 | return single_open(file, pnpconfig_proc_show, NULL); | ||
53 | } | ||
54 | |||
55 | static const struct file_operations pnpconfig_proc_fops = { | ||
56 | .owner = THIS_MODULE, | ||
57 | .open = pnpconfig_proc_open, | ||
58 | .read = seq_read, | ||
59 | .llseek = seq_lseek, | ||
60 | .release = single_release, | ||
61 | }; | ||
62 | |||
63 | static int escd_info_proc_show(struct seq_file *m, void *v) | ||
52 | { | 64 | { |
53 | struct escd_info_struc escd; | 65 | struct escd_info_struc escd; |
54 | 66 | ||
55 | if (pnp_bios_escd_info(&escd)) | 67 | if (pnp_bios_escd_info(&escd)) |
56 | return -EIO; | 68 | return -EIO; |
57 | return snprintf(buf, count, | 69 | seq_printf(m, "min_ESCD_write_size %d\n" |
58 | "min_ESCD_write_size %d\n" | ||
59 | "ESCD_size %d\n" | 70 | "ESCD_size %d\n" |
60 | "NVRAM_base 0x%x\n", | 71 | "NVRAM_base 0x%x\n", |
61 | escd.min_escd_write_size, | 72 | escd.min_escd_write_size, |
62 | escd.escd_size, escd.nv_storage_base); | 73 | escd.escd_size, escd.nv_storage_base); |
74 | return 0; | ||
63 | } | 75 | } |
64 | 76 | ||
77 | static int escd_info_proc_open(struct inode *inode, struct file *file) | ||
78 | { | ||
79 | return single_open(file, escd_info_proc_show, NULL); | ||
80 | } | ||
81 | |||
82 | static const struct file_operations escd_info_proc_fops = { | ||
83 | .owner = THIS_MODULE, | ||
84 | .open = escd_info_proc_open, | ||
85 | .read = seq_read, | ||
86 | .llseek = seq_lseek, | ||
87 | .release = single_release, | ||
88 | }; | ||
89 | |||
65 | #define MAX_SANE_ESCD_SIZE (32*1024) | 90 | #define MAX_SANE_ESCD_SIZE (32*1024) |
66 | static int proc_read_escd(char *buf, char **start, off_t pos, | 91 | static int escd_proc_show(struct seq_file *m, void *v) |
67 | int count, int *eof, void *data) | ||
68 | { | 92 | { |
69 | struct escd_info_struc escd; | 93 | struct escd_info_struc escd; |
70 | char *tmpbuf; | 94 | char *tmpbuf; |
71 | int escd_size, escd_left_to_read, n; | 95 | int escd_size; |
72 | 96 | ||
73 | if (pnp_bios_escd_info(&escd)) | 97 | if (pnp_bios_escd_info(&escd)) |
74 | return -EIO; | 98 | return -EIO; |
@@ -76,7 +100,7 @@ static int proc_read_escd(char *buf, char **start, off_t pos, | |||
76 | /* sanity check */ | 100 | /* sanity check */ |
77 | if (escd.escd_size > MAX_SANE_ESCD_SIZE) { | 101 | if (escd.escd_size > MAX_SANE_ESCD_SIZE) { |
78 | printk(KERN_ERR | 102 | printk(KERN_ERR |
79 | "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n"); | 103 | "PnPBIOS: %s: ESCD size reported by BIOS escd_info call is too great\n", __func__); |
80 | return -EFBIG; | 104 | return -EFBIG; |
81 | } | 105 | } |
82 | 106 | ||
@@ -94,56 +118,75 @@ static int proc_read_escd(char *buf, char **start, off_t pos, | |||
94 | 118 | ||
95 | /* sanity check */ | 119 | /* sanity check */ |
96 | if (escd_size > MAX_SANE_ESCD_SIZE) { | 120 | if (escd_size > MAX_SANE_ESCD_SIZE) { |
97 | printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by" | 121 | printk(KERN_ERR "PnPBIOS: %s: ESCD size reported by" |
98 | " BIOS read_escd call is too great\n"); | 122 | " BIOS read_escd call is too great\n", __func__); |
99 | kfree(tmpbuf); | 123 | kfree(tmpbuf); |
100 | return -EFBIG; | 124 | return -EFBIG; |
101 | } | 125 | } |
102 | 126 | ||
103 | escd_left_to_read = escd_size - pos; | 127 | seq_write(m, tmpbuf, escd_size); |
104 | if (escd_left_to_read < 0) | ||
105 | escd_left_to_read = 0; | ||
106 | if (escd_left_to_read == 0) | ||
107 | *eof = 1; | ||
108 | n = min(count, escd_left_to_read); | ||
109 | memcpy(buf, tmpbuf + pos, n); | ||
110 | kfree(tmpbuf); | 128 | kfree(tmpbuf); |
111 | *start = buf; | 129 | return 0; |
112 | return n; | ||
113 | } | 130 | } |
114 | 131 | ||
115 | static int proc_read_legacyres(char *buf, char **start, off_t pos, | 132 | static int escd_proc_open(struct inode *inode, struct file *file) |
116 | int count, int *eof, void *data) | 133 | { |
134 | return single_open(file, escd_proc_show, NULL); | ||
135 | } | ||
136 | |||
137 | static const struct file_operations escd_proc_fops = { | ||
138 | .owner = THIS_MODULE, | ||
139 | .open = escd_proc_open, | ||
140 | .read = seq_read, | ||
141 | .llseek = seq_lseek, | ||
142 | .release = single_release, | ||
143 | }; | ||
144 | |||
145 | static int pnp_legacyres_proc_show(struct seq_file *m, void *v) | ||
117 | { | 146 | { |
118 | /* Assume that the following won't overflow the buffer */ | 147 | void *buf; |
119 | if (pnp_bios_get_stat_res(buf)) | 148 | |
149 | buf = kmalloc(65536, GFP_KERNEL); | ||
150 | if (!buf) | ||
151 | return -ENOMEM; | ||
152 | if (pnp_bios_get_stat_res(buf)) { | ||
153 | kfree(buf); | ||
120 | return -EIO; | 154 | return -EIO; |
155 | } | ||
156 | |||
157 | seq_write(m, buf, 65536); | ||
158 | kfree(buf); | ||
159 | return 0; | ||
160 | } | ||
121 | 161 | ||
122 | return count; // FIXME: Return actual length | 162 | static int pnp_legacyres_proc_open(struct inode *inode, struct file *file) |
163 | { | ||
164 | return single_open(file, pnp_legacyres_proc_show, NULL); | ||
123 | } | 165 | } |
124 | 166 | ||
125 | static int proc_read_devices(char *buf, char **start, off_t pos, | 167 | static const struct file_operations pnp_legacyres_proc_fops = { |
126 | int count, int *eof, void *data) | 168 | .owner = THIS_MODULE, |
169 | .open = pnp_legacyres_proc_open, | ||
170 | .read = seq_read, | ||
171 | .llseek = seq_lseek, | ||
172 | .release = single_release, | ||
173 | }; | ||
174 | |||
175 | static int pnp_devices_proc_show(struct seq_file *m, void *v) | ||
127 | { | 176 | { |
128 | struct pnp_bios_node *node; | 177 | struct pnp_bios_node *node; |
129 | u8 nodenum; | 178 | u8 nodenum; |
130 | char *p = buf; | ||
131 | |||
132 | if (pos >= 0xff) | ||
133 | return 0; | ||
134 | 179 | ||
135 | node = kzalloc(node_info.max_node_size, GFP_KERNEL); | 180 | node = kzalloc(node_info.max_node_size, GFP_KERNEL); |
136 | if (!node) | 181 | if (!node) |
137 | return -ENOMEM; | 182 | return -ENOMEM; |
138 | 183 | ||
139 | for (nodenum = pos; nodenum < 0xff;) { | 184 | for (nodenum = 0; nodenum < 0xff;) { |
140 | u8 thisnodenum = nodenum; | 185 | u8 thisnodenum = nodenum; |
141 | /* 26 = the number of characters per line sprintf'ed */ | 186 | |
142 | if ((p - buf + 26) > count) | ||
143 | break; | ||
144 | if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node)) | 187 | if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node)) |
145 | break; | 188 | break; |
146 | p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", | 189 | seq_printf(m, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", |
147 | node->handle, node->eisa_id, | 190 | node->handle, node->eisa_id, |
148 | node->type_code[0], node->type_code[1], | 191 | node->type_code[0], node->type_code[1], |
149 | node->type_code[2], node->flags); | 192 | node->type_code[2], node->flags); |
@@ -153,20 +196,29 @@ static int proc_read_devices(char *buf, char **start, off_t pos, | |||
153 | "PnPBIOS: proc_read_devices:", | 196 | "PnPBIOS: proc_read_devices:", |
154 | (unsigned int)nodenum, | 197 | (unsigned int)nodenum, |
155 | (unsigned int)thisnodenum); | 198 | (unsigned int)thisnodenum); |
156 | *eof = 1; | ||
157 | break; | 199 | break; |
158 | } | 200 | } |
159 | } | 201 | } |
160 | kfree(node); | 202 | kfree(node); |
161 | if (nodenum == 0xff) | 203 | return 0; |
162 | *eof = 1; | 204 | } |
163 | *start = (char *)((off_t) nodenum - pos); | 205 | |
164 | return p - buf; | 206 | static int pnp_devices_proc_open(struct inode *inode, struct file *file) |
207 | { | ||
208 | return single_open(file, pnp_devices_proc_show, NULL); | ||
165 | } | 209 | } |
166 | 210 | ||
167 | static int proc_read_node(char *buf, char **start, off_t pos, | 211 | static const struct file_operations pnp_devices_proc_fops = { |
168 | int count, int *eof, void *data) | 212 | .owner = THIS_MODULE, |
213 | .open = pnp_devices_proc_open, | ||
214 | .read = seq_read, | ||
215 | .llseek = seq_lseek, | ||
216 | .release = single_release, | ||
217 | }; | ||
218 | |||
219 | static int pnpbios_proc_show(struct seq_file *m, void *v) | ||
169 | { | 220 | { |
221 | void *data = m->private; | ||
170 | struct pnp_bios_node *node; | 222 | struct pnp_bios_node *node; |
171 | int boot = (long)data >> 8; | 223 | int boot = (long)data >> 8; |
172 | u8 nodenum = (long)data; | 224 | u8 nodenum = (long)data; |
@@ -180,14 +232,20 @@ static int proc_read_node(char *buf, char **start, off_t pos, | |||
180 | return -EIO; | 232 | return -EIO; |
181 | } | 233 | } |
182 | len = node->size - sizeof(struct pnp_bios_node); | 234 | len = node->size - sizeof(struct pnp_bios_node); |
183 | memcpy(buf, node->data, len); | 235 | seq_write(m, node->data, len); |
184 | kfree(node); | 236 | kfree(node); |
185 | return len; | 237 | return 0; |
238 | } | ||
239 | |||
240 | static int pnpbios_proc_open(struct inode *inode, struct file *file) | ||
241 | { | ||
242 | return single_open(file, pnpbios_proc_show, PDE(inode)->data); | ||
186 | } | 243 | } |
187 | 244 | ||
188 | static int proc_write_node(struct file *file, const char __user * buf, | 245 | static ssize_t pnpbios_proc_write(struct file *file, const char __user *buf, |
189 | unsigned long count, void *data) | 246 | size_t count, loff_t *pos) |
190 | { | 247 | { |
248 | void *data = PDE(file->f_path.dentry->d_inode)->data; | ||
191 | struct pnp_bios_node *node; | 249 | struct pnp_bios_node *node; |
192 | int boot = (long)data >> 8; | 250 | int boot = (long)data >> 8; |
193 | u8 nodenum = (long)data; | 251 | u8 nodenum = (long)data; |
@@ -218,34 +276,33 @@ out: | |||
218 | return ret; | 276 | return ret; |
219 | } | 277 | } |
220 | 278 | ||
279 | static const struct file_operations pnpbios_proc_fops = { | ||
280 | .owner = THIS_MODULE, | ||
281 | .open = pnpbios_proc_open, | ||
282 | .read = seq_read, | ||
283 | .llseek = seq_lseek, | ||
284 | .release = single_release, | ||
285 | .write = pnpbios_proc_write, | ||
286 | }; | ||
287 | |||
221 | int pnpbios_interface_attach_device(struct pnp_bios_node *node) | 288 | int pnpbios_interface_attach_device(struct pnp_bios_node *node) |
222 | { | 289 | { |
223 | char name[3]; | 290 | char name[3]; |
224 | struct proc_dir_entry *ent; | ||
225 | 291 | ||
226 | sprintf(name, "%02x", node->handle); | 292 | sprintf(name, "%02x", node->handle); |
227 | 293 | ||
228 | if (!proc_pnp) | 294 | if (!proc_pnp) |
229 | return -EIO; | 295 | return -EIO; |
230 | if (!pnpbios_dont_use_current_config) { | 296 | if (!pnpbios_dont_use_current_config) { |
231 | ent = create_proc_entry(name, 0, proc_pnp); | 297 | proc_create_data(name, 0644, proc_pnp, &pnpbios_proc_fops, |
232 | if (ent) { | 298 | (void *)(long)(node->handle)); |
233 | ent->read_proc = proc_read_node; | ||
234 | ent->write_proc = proc_write_node; | ||
235 | ent->data = (void *)(long)(node->handle); | ||
236 | } | ||
237 | } | 299 | } |
238 | 300 | ||
239 | if (!proc_pnp_boot) | 301 | if (!proc_pnp_boot) |
240 | return -EIO; | 302 | return -EIO; |
241 | ent = create_proc_entry(name, 0, proc_pnp_boot); | 303 | if (proc_create_data(name, 0644, proc_pnp_boot, &pnpbios_proc_fops, |
242 | if (ent) { | 304 | (void *)(long)(node->handle + 0x100))) |
243 | ent->read_proc = proc_read_node; | ||
244 | ent->write_proc = proc_write_node; | ||
245 | ent->data = (void *)(long)(node->handle + 0x100); | ||
246 | return 0; | 305 | return 0; |
247 | } | ||
248 | |||
249 | return -EIO; | 306 | return -EIO; |
250 | } | 307 | } |
251 | 308 | ||
@@ -262,14 +319,11 @@ int __init pnpbios_proc_init(void) | |||
262 | proc_pnp_boot = proc_mkdir("boot", proc_pnp); | 319 | proc_pnp_boot = proc_mkdir("boot", proc_pnp); |
263 | if (!proc_pnp_boot) | 320 | if (!proc_pnp_boot) |
264 | return -EIO; | 321 | return -EIO; |
265 | create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL); | 322 | proc_create("devices", 0, proc_pnp, &pnp_devices_proc_fops); |
266 | create_proc_read_entry("configuration_info", 0, proc_pnp, | 323 | proc_create("configuration_info", 0, proc_pnp, &pnpconfig_proc_fops); |
267 | proc_read_pnpconfig, NULL); | 324 | proc_create("escd_info", 0, proc_pnp, &escd_info_proc_fops); |
268 | create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, | 325 | proc_create("escd", S_IRUSR, proc_pnp, &escd_proc_fops); |
269 | NULL); | 326 | proc_create("legacy_device_resources", 0, proc_pnp, &pnp_legacyres_proc_fops); |
270 | create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL); | ||
271 | create_proc_read_entry("legacy_device_resources", 0, proc_pnp, | ||
272 | proc_read_legacyres, NULL); | ||
273 | 327 | ||
274 | return 0; | 328 | return 0; |
275 | } | 329 | } |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 71fbd6e8edf7..8167e9e6827a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -242,6 +242,15 @@ config RTC_DRV_M41T80_WDT | |||
242 | If you say Y here you will get support for the | 242 | If you say Y here you will get support for the |
243 | watchdog timer in the ST M41T60 and M41T80 RTC chips series. | 243 | watchdog timer in the ST M41T60 and M41T80 RTC chips series. |
244 | 244 | ||
245 | config RTC_DRV_BQ32K | ||
246 | tristate "TI BQ32000" | ||
247 | help | ||
248 | If you say Y here you will get support for the TI | ||
249 | BQ32000 I2C RTC chip. | ||
250 | |||
251 | This driver can also be built as a module. If so, the module | ||
252 | will be called rtc-bq32k. | ||
253 | |||
245 | config RTC_DRV_DM355EVM | 254 | config RTC_DRV_DM355EVM |
246 | tristate "TI DaVinci DM355 EVM RTC" | 255 | tristate "TI DaVinci DM355 EVM RTC" |
247 | depends on MFD_DM355EVM_MSP | 256 | depends on MFD_DM355EVM_MSP |
@@ -592,15 +601,22 @@ config RTC_DRV_AB3100 | |||
592 | Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC | 601 | Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC |
593 | support. This chip contains a battery- and capacitor-backed RTC. | 602 | support. This chip contains a battery- and capacitor-backed RTC. |
594 | 603 | ||
604 | config RTC_DRV_NUC900 | ||
605 | tristate "NUC910/NUC920 RTC driver" | ||
606 | depends on RTC_CLASS && ARCH_W90X900 | ||
607 | help | ||
608 | If you say yes here you get support for the RTC subsystem of the | ||
609 | NUC910/NUC920 used in embedded systems. | ||
595 | 610 | ||
596 | comment "on-CPU RTC drivers" | 611 | comment "on-CPU RTC drivers" |
597 | 612 | ||
598 | config RTC_DRV_OMAP | 613 | config RTC_DRV_OMAP |
599 | tristate "TI OMAP1" | 614 | tristate "TI OMAP1" |
600 | depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 | 615 | depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX |
601 | help | 616 | help |
602 | Say "yes" here to support the real time clock on TI OMAP1 chips. | 617 | Say "yes" here to support the real time clock on TI OMAP1 and |
603 | This driver can also be built as a module called rtc-omap. | 618 | DA8xx/OMAP-L13x chips. This driver can also be built as a |
619 | module called rtc-omap. | ||
604 | 620 | ||
605 | config RTC_DRV_S3C | 621 | config RTC_DRV_S3C |
606 | tristate "Samsung S3C series SoC RTC" | 622 | tristate "Samsung S3C series SoC RTC" |
@@ -846,4 +862,10 @@ config RTC_DRV_PCAP | |||
846 | If you say Y here you will get support for the RTC found on | 862 | If you say Y here you will get support for the RTC found on |
847 | the PCAP2 ASIC used on some Motorola phones. | 863 | the PCAP2 ASIC used on some Motorola phones. |
848 | 864 | ||
865 | config RTC_DRV_MC13783 | ||
866 | depends on MFD_MC13783 | ||
867 | tristate "Freescale MC13783 RTC" | ||
868 | help | ||
869 | This enables support for the Freescale MC13783 PMIC RTC | ||
870 | |||
849 | endif # RTC_CLASS | 871 | endif # RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 7da6efb3e953..e5160fddc446 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o | |||
23 | obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o | 23 | obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o |
24 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o | 24 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o |
25 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o | 25 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o |
26 | obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o | ||
26 | obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o | 27 | obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o |
27 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o | 28 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o |
28 | obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o | 29 | obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o |
@@ -52,8 +53,10 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | |||
52 | obj-$(CONFIG_RTC_MXC) += rtc-mxc.o | 53 | obj-$(CONFIG_RTC_MXC) += rtc-mxc.o |
53 | obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o | 54 | obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o |
54 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o | 55 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o |
56 | obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o | ||
55 | obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o | 57 | obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o |
56 | obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o | 58 | obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o |
59 | obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o | ||
57 | obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o | 60 | obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o |
58 | obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o | 61 | obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o |
59 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 62 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index e1ec33e40e38..8825695777df 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c | |||
@@ -256,6 +256,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev) | |||
256 | goto out_iounmap; | 256 | goto out_iounmap; |
257 | } | 257 | } |
258 | 258 | ||
259 | platform_set_drvdata(pdev, rtc); | ||
260 | |||
259 | rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, | 261 | rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, |
260 | &at32_rtc_ops, THIS_MODULE); | 262 | &at32_rtc_ops, THIS_MODULE); |
261 | if (IS_ERR(rtc->rtc)) { | 263 | if (IS_ERR(rtc->rtc)) { |
@@ -264,7 +266,6 @@ static int __init at32_rtc_probe(struct platform_device *pdev) | |||
264 | goto out_free_irq; | 266 | goto out_free_irq; |
265 | } | 267 | } |
266 | 268 | ||
267 | platform_set_drvdata(pdev, rtc); | ||
268 | device_init_wakeup(&pdev->dev, 1); | 269 | device_init_wakeup(&pdev->dev, 1); |
269 | 270 | ||
270 | dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", | 271 | dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", |
@@ -273,6 +274,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) | |||
273 | return 0; | 274 | return 0; |
274 | 275 | ||
275 | out_free_irq: | 276 | out_free_irq: |
277 | platform_set_drvdata(pdev, NULL); | ||
276 | free_irq(irq, rtc); | 278 | free_irq(irq, rtc); |
277 | out_iounmap: | 279 | out_iounmap: |
278 | iounmap(rtc->regs); | 280 | iounmap(rtc->regs); |
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c new file mode 100644 index 000000000000..408cc8f735be --- /dev/null +++ b/drivers/rtc/rtc-bq32k.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Driver for TI BQ32000 RTC. | ||
3 | * | ||
4 | * Copyright (C) 2009 Semihalf. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/bcd.h> | ||
17 | |||
18 | #define BQ32K_SECONDS 0x00 /* Seconds register address */ | ||
19 | #define BQ32K_SECONDS_MASK 0x7F /* Mask over seconds value */ | ||
20 | #define BQ32K_STOP 0x80 /* Oscillator Stop flat */ | ||
21 | |||
22 | #define BQ32K_MINUTES 0x01 /* Minutes register address */ | ||
23 | #define BQ32K_MINUTES_MASK 0x7F /* Mask over minutes value */ | ||
24 | #define BQ32K_OF 0x80 /* Oscillator Failure flag */ | ||
25 | |||
26 | #define BQ32K_HOURS_MASK 0x3F /* Mask over hours value */ | ||
27 | #define BQ32K_CENT 0x40 /* Century flag */ | ||
28 | #define BQ32K_CENT_EN 0x80 /* Century flag enable bit */ | ||
29 | |||
30 | struct bq32k_regs { | ||
31 | uint8_t seconds; | ||
32 | uint8_t minutes; | ||
33 | uint8_t cent_hours; | ||
34 | uint8_t day; | ||
35 | uint8_t date; | ||
36 | uint8_t month; | ||
37 | uint8_t years; | ||
38 | }; | ||
39 | |||
40 | static struct i2c_driver bq32k_driver; | ||
41 | |||
42 | static int bq32k_read(struct device *dev, void *data, uint8_t off, uint8_t len) | ||
43 | { | ||
44 | struct i2c_client *client = to_i2c_client(dev); | ||
45 | struct i2c_msg msgs[] = { | ||
46 | { | ||
47 | .addr = client->addr, | ||
48 | .flags = 0, | ||
49 | .len = 1, | ||
50 | .buf = &off, | ||
51 | }, { | ||
52 | .addr = client->addr, | ||
53 | .flags = I2C_M_RD, | ||
54 | .len = len, | ||
55 | .buf = data, | ||
56 | } | ||
57 | }; | ||
58 | |||
59 | if (i2c_transfer(client->adapter, msgs, 2) == 2) | ||
60 | return 0; | ||
61 | |||
62 | return -EIO; | ||
63 | } | ||
64 | |||
65 | static int bq32k_write(struct device *dev, void *data, uint8_t off, uint8_t len) | ||
66 | { | ||
67 | struct i2c_client *client = to_i2c_client(dev); | ||
68 | uint8_t buffer[len + 1]; | ||
69 | |||
70 | buffer[0] = off; | ||
71 | memcpy(&buffer[1], data, len); | ||
72 | |||
73 | if (i2c_master_send(client, buffer, len + 1) == len + 1) | ||
74 | return 0; | ||
75 | |||
76 | return -EIO; | ||
77 | } | ||
78 | |||
79 | static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
80 | { | ||
81 | struct bq32k_regs regs; | ||
82 | int error; | ||
83 | |||
84 | error = bq32k_read(dev, ®s, 0, sizeof(regs)); | ||
85 | if (error) | ||
86 | return error; | ||
87 | |||
88 | tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK); | ||
89 | tm->tm_min = bcd2bin(regs.minutes & BQ32K_SECONDS_MASK); | ||
90 | tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK); | ||
91 | tm->tm_mday = bcd2bin(regs.date); | ||
92 | tm->tm_wday = bcd2bin(regs.day) - 1; | ||
93 | tm->tm_mon = bcd2bin(regs.month) - 1; | ||
94 | tm->tm_year = bcd2bin(regs.years) + | ||
95 | ((regs.cent_hours & BQ32K_CENT) ? 100 : 0); | ||
96 | |||
97 | return rtc_valid_tm(tm); | ||
98 | } | ||
99 | |||
100 | static int bq32k_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
101 | { | ||
102 | struct bq32k_regs regs; | ||
103 | |||
104 | regs.seconds = bin2bcd(tm->tm_sec); | ||
105 | regs.minutes = bin2bcd(tm->tm_min); | ||
106 | regs.cent_hours = bin2bcd(tm->tm_hour) | BQ32K_CENT_EN; | ||
107 | regs.day = bin2bcd(tm->tm_wday + 1); | ||
108 | regs.date = bin2bcd(tm->tm_mday); | ||
109 | regs.month = bin2bcd(tm->tm_mon + 1); | ||
110 | |||
111 | if (tm->tm_year >= 100) { | ||
112 | regs.cent_hours |= BQ32K_CENT; | ||
113 | regs.years = bin2bcd(tm->tm_year - 100); | ||
114 | } else | ||
115 | regs.years = bin2bcd(tm->tm_year); | ||
116 | |||
117 | return bq32k_write(dev, ®s, 0, sizeof(regs)); | ||
118 | } | ||
119 | |||
120 | static const struct rtc_class_ops bq32k_rtc_ops = { | ||
121 | .read_time = bq32k_rtc_read_time, | ||
122 | .set_time = bq32k_rtc_set_time, | ||
123 | }; | ||
124 | |||
125 | static int bq32k_probe(struct i2c_client *client, | ||
126 | const struct i2c_device_id *id) | ||
127 | { | ||
128 | struct device *dev = &client->dev; | ||
129 | struct rtc_device *rtc; | ||
130 | uint8_t reg; | ||
131 | int error; | ||
132 | |||
133 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
134 | return -ENODEV; | ||
135 | |||
136 | /* Check Oscillator Stop flag */ | ||
137 | error = bq32k_read(dev, ®, BQ32K_SECONDS, 1); | ||
138 | if (!error && (reg & BQ32K_STOP)) { | ||
139 | dev_warn(dev, "Oscillator was halted. Restarting...\n"); | ||
140 | reg &= ~BQ32K_STOP; | ||
141 | error = bq32k_write(dev, ®, BQ32K_SECONDS, 1); | ||
142 | } | ||
143 | if (error) | ||
144 | return error; | ||
145 | |||
146 | /* Check Oscillator Failure flag */ | ||
147 | error = bq32k_read(dev, ®, BQ32K_MINUTES, 1); | ||
148 | if (!error && (reg & BQ32K_OF)) { | ||
149 | dev_warn(dev, "Oscillator Failure. Check RTC battery.\n"); | ||
150 | reg &= ~BQ32K_OF; | ||
151 | error = bq32k_write(dev, ®, BQ32K_MINUTES, 1); | ||
152 | } | ||
153 | if (error) | ||
154 | return error; | ||
155 | |||
156 | rtc = rtc_device_register(bq32k_driver.driver.name, &client->dev, | ||
157 | &bq32k_rtc_ops, THIS_MODULE); | ||
158 | if (IS_ERR(rtc)) | ||
159 | return PTR_ERR(rtc); | ||
160 | |||
161 | i2c_set_clientdata(client, rtc); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int __devexit bq32k_remove(struct i2c_client *client) | ||
167 | { | ||
168 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
169 | |||
170 | rtc_device_unregister(rtc); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct i2c_device_id bq32k_id[] = { | ||
175 | { "bq32000", 0 }, | ||
176 | { } | ||
177 | }; | ||
178 | MODULE_DEVICE_TABLE(i2c, bq32k_id); | ||
179 | |||
180 | static struct i2c_driver bq32k_driver = { | ||
181 | .driver = { | ||
182 | .name = "bq32k", | ||
183 | .owner = THIS_MODULE, | ||
184 | }, | ||
185 | .probe = bq32k_probe, | ||
186 | .remove = __devexit_p(bq32k_remove), | ||
187 | .id_table = bq32k_id, | ||
188 | }; | ||
189 | |||
190 | static __init int bq32k_init(void) | ||
191 | { | ||
192 | return i2c_add_driver(&bq32k_driver); | ||
193 | } | ||
194 | module_init(bq32k_init); | ||
195 | |||
196 | static __exit void bq32k_exit(void) | ||
197 | { | ||
198 | i2c_del_driver(&bq32k_driver); | ||
199 | } | ||
200 | module_exit(bq32k_exit); | ||
201 | |||
202 | MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>"); | ||
203 | MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver"); | ||
204 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index d00a274df8fc..280fe48ada0b 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c | |||
@@ -169,6 +169,8 @@ static int __devinit bq4802_probe(struct platform_device *pdev) | |||
169 | goto out_free; | 169 | goto out_free; |
170 | } | 170 | } |
171 | 171 | ||
172 | platform_set_drvdata(pdev, p); | ||
173 | |||
172 | p->rtc = rtc_device_register("bq4802", &pdev->dev, | 174 | p->rtc = rtc_device_register("bq4802", &pdev->dev, |
173 | &bq4802_ops, THIS_MODULE); | 175 | &bq4802_ops, THIS_MODULE); |
174 | if (IS_ERR(p->rtc)) { | 176 | if (IS_ERR(p->rtc)) { |
@@ -176,7 +178,6 @@ static int __devinit bq4802_probe(struct platform_device *pdev) | |||
176 | goto out_iounmap; | 178 | goto out_iounmap; |
177 | } | 179 | } |
178 | 180 | ||
179 | platform_set_drvdata(pdev, p); | ||
180 | err = 0; | 181 | err = 0; |
181 | out: | 182 | out: |
182 | return err; | 183 | return err; |
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f7a4701bf863..eb154dc57164 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -420,49 +420,43 @@ static int cmos_irq_set_state(struct device *dev, int enabled) | |||
420 | return 0; | 420 | return 0; |
421 | } | 421 | } |
422 | 422 | ||
423 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) | 423 | static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) |
424 | |||
425 | static int | ||
426 | cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
427 | { | 424 | { |
428 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 425 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
429 | unsigned long flags; | 426 | unsigned long flags; |
430 | 427 | ||
431 | switch (cmd) { | 428 | if (!is_valid_irq(cmos->irq)) |
432 | case RTC_AIE_OFF: | 429 | return -EINVAL; |
433 | case RTC_AIE_ON: | ||
434 | case RTC_UIE_OFF: | ||
435 | case RTC_UIE_ON: | ||
436 | if (!is_valid_irq(cmos->irq)) | ||
437 | return -EINVAL; | ||
438 | break; | ||
439 | /* PIE ON/OFF is handled by cmos_irq_set_state() */ | ||
440 | default: | ||
441 | return -ENOIOCTLCMD; | ||
442 | } | ||
443 | 430 | ||
444 | spin_lock_irqsave(&rtc_lock, flags); | 431 | spin_lock_irqsave(&rtc_lock, flags); |
445 | switch (cmd) { | 432 | |
446 | case RTC_AIE_OFF: /* alarm off */ | 433 | if (enabled) |
447 | cmos_irq_disable(cmos, RTC_AIE); | ||
448 | break; | ||
449 | case RTC_AIE_ON: /* alarm on */ | ||
450 | cmos_irq_enable(cmos, RTC_AIE); | 434 | cmos_irq_enable(cmos, RTC_AIE); |
451 | break; | 435 | else |
452 | case RTC_UIE_OFF: /* update off */ | 436 | cmos_irq_disable(cmos, RTC_AIE); |
453 | cmos_irq_disable(cmos, RTC_UIE); | 437 | |
454 | break; | ||
455 | case RTC_UIE_ON: /* update on */ | ||
456 | cmos_irq_enable(cmos, RTC_UIE); | ||
457 | break; | ||
458 | } | ||
459 | spin_unlock_irqrestore(&rtc_lock, flags); | 438 | spin_unlock_irqrestore(&rtc_lock, flags); |
460 | return 0; | 439 | return 0; |
461 | } | 440 | } |
462 | 441 | ||
463 | #else | 442 | static int cmos_update_irq_enable(struct device *dev, unsigned int enabled) |
464 | #define cmos_rtc_ioctl NULL | 443 | { |
465 | #endif | 444 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
445 | unsigned long flags; | ||
446 | |||
447 | if (!is_valid_irq(cmos->irq)) | ||
448 | return -EINVAL; | ||
449 | |||
450 | spin_lock_irqsave(&rtc_lock, flags); | ||
451 | |||
452 | if (enabled) | ||
453 | cmos_irq_enable(cmos, RTC_UIE); | ||
454 | else | ||
455 | cmos_irq_disable(cmos, RTC_UIE); | ||
456 | |||
457 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
458 | return 0; | ||
459 | } | ||
466 | 460 | ||
467 | #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) | 461 | #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) |
468 | 462 | ||
@@ -503,14 +497,15 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq) | |||
503 | #endif | 497 | #endif |
504 | 498 | ||
505 | static const struct rtc_class_ops cmos_rtc_ops = { | 499 | static const struct rtc_class_ops cmos_rtc_ops = { |
506 | .ioctl = cmos_rtc_ioctl, | 500 | .read_time = cmos_read_time, |
507 | .read_time = cmos_read_time, | 501 | .set_time = cmos_set_time, |
508 | .set_time = cmos_set_time, | 502 | .read_alarm = cmos_read_alarm, |
509 | .read_alarm = cmos_read_alarm, | 503 | .set_alarm = cmos_set_alarm, |
510 | .set_alarm = cmos_set_alarm, | 504 | .proc = cmos_procfs, |
511 | .proc = cmos_procfs, | 505 | .irq_set_freq = cmos_irq_set_freq, |
512 | .irq_set_freq = cmos_irq_set_freq, | 506 | .irq_set_state = cmos_irq_set_state, |
513 | .irq_set_state = cmos_irq_set_state, | 507 | .alarm_irq_enable = cmos_alarm_irq_enable, |
508 | .update_irq_enable = cmos_update_irq_enable, | ||
514 | }; | 509 | }; |
515 | 510 | ||
516 | /*----------------------------------------------------------------*/ | 511 | /*----------------------------------------------------------------*/ |
@@ -871,8 +866,9 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) | |||
871 | mask = RTC_IRQMASK; | 866 | mask = RTC_IRQMASK; |
872 | tmp &= ~mask; | 867 | tmp &= ~mask; |
873 | CMOS_WRITE(tmp, RTC_CONTROL); | 868 | CMOS_WRITE(tmp, RTC_CONTROL); |
874 | hpet_mask_rtc_irq_bit(mask); | ||
875 | 869 | ||
870 | /* shut down hpet emulation - we don't need it for alarm */ | ||
871 | hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE); | ||
876 | cmos_checkintr(cmos, tmp); | 872 | cmos_checkintr(cmos, tmp); |
877 | } | 873 | } |
878 | spin_unlock_irq(&rtc_lock); | 874 | spin_unlock_irq(&rtc_lock); |
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 1e73c8f42e38..532acf9b05d8 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c | |||
@@ -143,7 +143,6 @@ static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
143 | #ifdef RTC_SET_CHARGE | 143 | #ifdef RTC_SET_CHARGE |
144 | case RTC_SET_CHARGE: | 144 | case RTC_SET_CHARGE: |
145 | { | 145 | { |
146 | struct ds1302_rtc *rtc = dev_get_drvdata(dev); | ||
147 | int tcs_val; | 146 | int tcs_val; |
148 | 147 | ||
149 | if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) | 148 | if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) |
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 2736b11a1b1e..259db7f3535b 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c | |||
@@ -617,7 +617,6 @@ static struct bin_attribute nvram = { | |||
617 | static int __devinit ds1305_probe(struct spi_device *spi) | 617 | static int __devinit ds1305_probe(struct spi_device *spi) |
618 | { | 618 | { |
619 | struct ds1305 *ds1305; | 619 | struct ds1305 *ds1305; |
620 | struct rtc_device *rtc; | ||
621 | int status; | 620 | int status; |
622 | u8 addr, value; | 621 | u8 addr, value; |
623 | struct ds1305_platform_data *pdata = spi->dev.platform_data; | 622 | struct ds1305_platform_data *pdata = spi->dev.platform_data; |
@@ -756,14 +755,13 @@ static int __devinit ds1305_probe(struct spi_device *spi) | |||
756 | dev_dbg(&spi->dev, "AM/PM\n"); | 755 | dev_dbg(&spi->dev, "AM/PM\n"); |
757 | 756 | ||
758 | /* register RTC ... from here on, ds1305->ctrl needs locking */ | 757 | /* register RTC ... from here on, ds1305->ctrl needs locking */ |
759 | rtc = rtc_device_register("ds1305", &spi->dev, | 758 | ds1305->rtc = rtc_device_register("ds1305", &spi->dev, |
760 | &ds1305_ops, THIS_MODULE); | 759 | &ds1305_ops, THIS_MODULE); |
761 | if (IS_ERR(rtc)) { | 760 | if (IS_ERR(ds1305->rtc)) { |
762 | status = PTR_ERR(rtc); | 761 | status = PTR_ERR(ds1305->rtc); |
763 | dev_dbg(&spi->dev, "register rtc --> %d\n", status); | 762 | dev_dbg(&spi->dev, "register rtc --> %d\n", status); |
764 | goto fail0; | 763 | goto fail0; |
765 | } | 764 | } |
766 | ds1305->rtc = rtc; | ||
767 | 765 | ||
768 | /* Maybe set up alarm IRQ; be ready to handle it triggering right | 766 | /* Maybe set up alarm IRQ; be ready to handle it triggering right |
769 | * away. NOTE that we don't share this. The signal is active low, | 767 | * away. NOTE that we don't share this. The signal is active low, |
@@ -774,7 +772,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) | |||
774 | if (spi->irq) { | 772 | if (spi->irq) { |
775 | INIT_WORK(&ds1305->work, ds1305_work); | 773 | INIT_WORK(&ds1305->work, ds1305_work); |
776 | status = request_irq(spi->irq, ds1305_irq, | 774 | status = request_irq(spi->irq, ds1305_irq, |
777 | 0, dev_name(&rtc->dev), ds1305); | 775 | 0, dev_name(&ds1305->rtc->dev), ds1305); |
778 | if (status < 0) { | 776 | if (status < 0) { |
779 | dev_dbg(&spi->dev, "request_irq %d --> %d\n", | 777 | dev_dbg(&spi->dev, "request_irq %d --> %d\n", |
780 | spi->irq, status); | 778 | spi->irq, status); |
@@ -794,7 +792,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) | |||
794 | fail2: | 792 | fail2: |
795 | free_irq(spi->irq, ds1305); | 793 | free_irq(spi->irq, ds1305); |
796 | fail1: | 794 | fail1: |
797 | rtc_device_unregister(rtc); | 795 | rtc_device_unregister(ds1305->rtc); |
798 | fail0: | 796 | fail0: |
799 | kfree(ds1305); | 797 | kfree(ds1305); |
800 | return status; | 798 | return status; |
@@ -802,7 +800,7 @@ fail0: | |||
802 | 800 | ||
803 | static int __devexit ds1305_remove(struct spi_device *spi) | 801 | static int __devexit ds1305_remove(struct spi_device *spi) |
804 | { | 802 | { |
805 | struct ds1305 *ds1305 = spi_get_drvdata(spi); | 803 | struct ds1305 *ds1305 = spi_get_drvdata(spi); |
806 | 804 | ||
807 | sysfs_remove_bin_file(&spi->dev.kobj, &nvram); | 805 | sysfs_remove_bin_file(&spi->dev.kobj, &nvram); |
808 | 806 | ||
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index eb99ee4fa0f5..8a99da6f2f24 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -874,7 +874,7 @@ read_rtc: | |||
874 | } | 874 | } |
875 | 875 | ||
876 | if (want_irq) { | 876 | if (want_irq) { |
877 | err = request_irq(client->irq, ds1307_irq, 0, | 877 | err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, |
878 | ds1307->rtc->name, client); | 878 | ds1307->rtc->name, client); |
879 | if (err) { | 879 | if (err) { |
880 | dev_err(&client->dev, | 880 | dev_err(&client->dev, |
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 539676e25fd8..4166b84cb514 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c | |||
@@ -87,7 +87,6 @@ enum ds1511reg { | |||
87 | struct rtc_plat_data { | 87 | struct rtc_plat_data { |
88 | struct rtc_device *rtc; | 88 | struct rtc_device *rtc; |
89 | void __iomem *ioaddr; /* virtual base address */ | 89 | void __iomem *ioaddr; /* virtual base address */ |
90 | unsigned long baseaddr; /* physical base address */ | ||
91 | int size; /* amount of memory mapped */ | 90 | int size; /* amount of memory mapped */ |
92 | int irq; | 91 | int irq; |
93 | unsigned int irqen; | 92 | unsigned int irqen; |
@@ -95,6 +94,7 @@ struct rtc_plat_data { | |||
95 | int alrm_min; | 94 | int alrm_min; |
96 | int alrm_hour; | 95 | int alrm_hour; |
97 | int alrm_mday; | 96 | int alrm_mday; |
97 | spinlock_t lock; | ||
98 | }; | 98 | }; |
99 | 99 | ||
100 | static DEFINE_SPINLOCK(ds1511_lock); | 100 | static DEFINE_SPINLOCK(ds1511_lock); |
@@ -302,7 +302,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
302 | { | 302 | { |
303 | unsigned long flags; | 303 | unsigned long flags; |
304 | 304 | ||
305 | spin_lock_irqsave(&pdata->rtc->irq_lock, flags); | 305 | spin_lock_irqsave(&pdata->lock, flags); |
306 | rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | 306 | rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? |
307 | 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, | 307 | 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, |
308 | RTC_ALARM_DATE); | 308 | RTC_ALARM_DATE); |
@@ -317,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
317 | RTC_ALARM_SEC); | 317 | RTC_ALARM_SEC); |
318 | rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); | 318 | rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); |
319 | rtc_read(RTC_CMD1); /* clear interrupts */ | 319 | rtc_read(RTC_CMD1); /* clear interrupts */ |
320 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); | 320 | spin_unlock_irqrestore(&pdata->lock, flags); |
321 | } | 321 | } |
322 | 322 | ||
323 | static int | 323 | static int |
@@ -362,61 +362,63 @@ ds1511_interrupt(int irq, void *dev_id) | |||
362 | { | 362 | { |
363 | struct platform_device *pdev = dev_id; | 363 | struct platform_device *pdev = dev_id; |
364 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 364 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
365 | unsigned long events = RTC_IRQF; | 365 | unsigned long events = 0; |
366 | 366 | ||
367 | spin_lock(&pdata->lock); | ||
367 | /* | 368 | /* |
368 | * read and clear interrupt | 369 | * read and clear interrupt |
369 | */ | 370 | */ |
370 | if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { | 371 | if (rtc_read(RTC_CMD1) & DS1511_IRQF) { |
371 | return IRQ_NONE; | 372 | events = RTC_IRQF; |
372 | } | 373 | if (rtc_read(RTC_ALARM_SEC) & 0x80) |
373 | if (rtc_read(RTC_ALARM_SEC) & 0x80) { | 374 | events |= RTC_UF; |
374 | events |= RTC_UF; | 375 | else |
375 | } else { | 376 | events |= RTC_AF; |
376 | events |= RTC_AF; | 377 | if (likely(pdata->rtc)) |
377 | } | 378 | rtc_update_irq(pdata->rtc, 1, events); |
378 | rtc_update_irq(pdata->rtc, 1, events); | 379 | } |
379 | return IRQ_HANDLED; | 380 | spin_unlock(&pdata->lock); |
381 | return events ? IRQ_HANDLED : IRQ_NONE; | ||
380 | } | 382 | } |
381 | 383 | ||
382 | static int | 384 | static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
383 | ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
384 | { | 385 | { |
385 | struct platform_device *pdev = to_platform_device(dev); | 386 | struct platform_device *pdev = to_platform_device(dev); |
386 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 387 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
387 | 388 | ||
388 | if (pdata->irq <= 0) { | 389 | if (pdata->irq <= 0) |
389 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | 390 | return -EINVAL; |
390 | } | 391 | if (enabled) |
391 | switch (cmd) { | ||
392 | case RTC_AIE_OFF: | ||
393 | pdata->irqen &= ~RTC_AF; | ||
394 | ds1511_rtc_update_alarm(pdata); | ||
395 | break; | ||
396 | case RTC_AIE_ON: | ||
397 | pdata->irqen |= RTC_AF; | 392 | pdata->irqen |= RTC_AF; |
398 | ds1511_rtc_update_alarm(pdata); | 393 | else |
399 | break; | 394 | pdata->irqen &= ~RTC_AF; |
400 | case RTC_UIE_OFF: | 395 | ds1511_rtc_update_alarm(pdata); |
401 | pdata->irqen &= ~RTC_UF; | 396 | return 0; |
402 | ds1511_rtc_update_alarm(pdata); | 397 | } |
403 | break; | 398 | |
404 | case RTC_UIE_ON: | 399 | static int ds1511_rtc_update_irq_enable(struct device *dev, |
400 | unsigned int enabled) | ||
401 | { | ||
402 | struct platform_device *pdev = to_platform_device(dev); | ||
403 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
404 | |||
405 | if (pdata->irq <= 0) | ||
406 | return -EINVAL; | ||
407 | if (enabled) | ||
405 | pdata->irqen |= RTC_UF; | 408 | pdata->irqen |= RTC_UF; |
406 | ds1511_rtc_update_alarm(pdata); | 409 | else |
407 | break; | 410 | pdata->irqen &= ~RTC_UF; |
408 | default: | 411 | ds1511_rtc_update_alarm(pdata); |
409 | return -ENOIOCTLCMD; | ||
410 | } | ||
411 | return 0; | 412 | return 0; |
412 | } | 413 | } |
413 | 414 | ||
414 | static const struct rtc_class_ops ds1511_rtc_ops = { | 415 | static const struct rtc_class_ops ds1511_rtc_ops = { |
415 | .read_time = ds1511_rtc_read_time, | 416 | .read_time = ds1511_rtc_read_time, |
416 | .set_time = ds1511_rtc_set_time, | 417 | .set_time = ds1511_rtc_set_time, |
417 | .read_alarm = ds1511_rtc_read_alarm, | 418 | .read_alarm = ds1511_rtc_read_alarm, |
418 | .set_alarm = ds1511_rtc_set_alarm, | 419 | .set_alarm = ds1511_rtc_set_alarm, |
419 | .ioctl = ds1511_rtc_ioctl, | 420 | .alarm_irq_enable = ds1511_rtc_alarm_irq_enable, |
421 | .update_irq_enable = ds1511_rtc_update_irq_enable, | ||
420 | }; | 422 | }; |
421 | 423 | ||
422 | static ssize_t | 424 | static ssize_t |
@@ -492,29 +494,23 @@ ds1511_rtc_probe(struct platform_device *pdev) | |||
492 | { | 494 | { |
493 | struct rtc_device *rtc; | 495 | struct rtc_device *rtc; |
494 | struct resource *res; | 496 | struct resource *res; |
495 | struct rtc_plat_data *pdata = NULL; | 497 | struct rtc_plat_data *pdata; |
496 | int ret = 0; | 498 | int ret = 0; |
497 | 499 | ||
498 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 500 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
499 | if (!res) { | 501 | if (!res) { |
500 | return -ENODEV; | 502 | return -ENODEV; |
501 | } | 503 | } |
502 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 504 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
503 | if (!pdata) { | 505 | if (!pdata) |
504 | return -ENOMEM; | 506 | return -ENOMEM; |
505 | } | ||
506 | pdata->size = res->end - res->start + 1; | 507 | pdata->size = res->end - res->start + 1; |
507 | if (!request_mem_region(res->start, pdata->size, pdev->name)) { | 508 | if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, |
508 | ret = -EBUSY; | 509 | pdev->name)) |
509 | goto out; | 510 | return -EBUSY; |
510 | } | 511 | ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size); |
511 | pdata->baseaddr = res->start; | 512 | if (!ds1511_base) |
512 | pdata->size = pdata->size; | 513 | return -ENOMEM; |
513 | ds1511_base = ioremap(pdata->baseaddr, pdata->size); | ||
514 | if (!ds1511_base) { | ||
515 | ret = -ENOMEM; | ||
516 | goto out; | ||
517 | } | ||
518 | pdata->ioaddr = ds1511_base; | 514 | pdata->ioaddr = ds1511_base; |
519 | pdata->irq = platform_get_irq(pdev, 0); | 515 | pdata->irq = platform_get_irq(pdev, 0); |
520 | 516 | ||
@@ -540,13 +536,15 @@ ds1511_rtc_probe(struct platform_device *pdev) | |||
540 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 536 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
541 | } | 537 | } |
542 | 538 | ||
539 | spin_lock_init(&pdata->lock); | ||
540 | platform_set_drvdata(pdev, pdata); | ||
543 | /* | 541 | /* |
544 | * if the platform has an interrupt in mind for this device, | 542 | * if the platform has an interrupt in mind for this device, |
545 | * then by all means, set it | 543 | * then by all means, set it |
546 | */ | 544 | */ |
547 | if (pdata->irq > 0) { | 545 | if (pdata->irq > 0) { |
548 | rtc_read(RTC_CMD1); | 546 | rtc_read(RTC_CMD1); |
549 | if (request_irq(pdata->irq, ds1511_interrupt, | 547 | if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt, |
550 | IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { | 548 | IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { |
551 | 549 | ||
552 | dev_warn(&pdev->dev, "interrupt not available.\n"); | 550 | dev_warn(&pdev->dev, "interrupt not available.\n"); |
@@ -556,33 +554,13 @@ ds1511_rtc_probe(struct platform_device *pdev) | |||
556 | 554 | ||
557 | rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, | 555 | rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, |
558 | THIS_MODULE); | 556 | THIS_MODULE); |
559 | if (IS_ERR(rtc)) { | 557 | if (IS_ERR(rtc)) |
560 | ret = PTR_ERR(rtc); | 558 | return PTR_ERR(rtc); |
561 | goto out; | ||
562 | } | ||
563 | pdata->rtc = rtc; | 559 | pdata->rtc = rtc; |
564 | platform_set_drvdata(pdev, pdata); | 560 | |
565 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); | 561 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); |
566 | if (ret) { | 562 | if (ret) |
567 | goto out; | ||
568 | } | ||
569 | return 0; | ||
570 | out: | ||
571 | if (pdata->rtc) { | ||
572 | rtc_device_unregister(pdata->rtc); | 563 | rtc_device_unregister(pdata->rtc); |
573 | } | ||
574 | if (pdata->irq > 0) { | ||
575 | free_irq(pdata->irq, pdev); | ||
576 | } | ||
577 | if (ds1511_base) { | ||
578 | iounmap(ds1511_base); | ||
579 | ds1511_base = NULL; | ||
580 | } | ||
581 | if (pdata->baseaddr) { | ||
582 | release_mem_region(pdata->baseaddr, pdata->size); | ||
583 | } | ||
584 | |||
585 | kfree(pdata); | ||
586 | return ret; | 564 | return ret; |
587 | } | 565 | } |
588 | 566 | ||
@@ -593,19 +571,13 @@ ds1511_rtc_remove(struct platform_device *pdev) | |||
593 | 571 | ||
594 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); | 572 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); |
595 | rtc_device_unregister(pdata->rtc); | 573 | rtc_device_unregister(pdata->rtc); |
596 | pdata->rtc = NULL; | ||
597 | if (pdata->irq > 0) { | 574 | if (pdata->irq > 0) { |
598 | /* | 575 | /* |
599 | * disable the alarm interrupt | 576 | * disable the alarm interrupt |
600 | */ | 577 | */ |
601 | rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); | 578 | rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); |
602 | rtc_read(RTC_CMD1); | 579 | rtc_read(RTC_CMD1); |
603 | free_irq(pdata->irq, pdev); | ||
604 | } | 580 | } |
605 | iounmap(pdata->ioaddr); | ||
606 | ds1511_base = NULL; | ||
607 | release_mem_region(pdata->baseaddr, pdata->size); | ||
608 | kfree(pdata); | ||
609 | return 0; | 581 | return 0; |
610 | } | 582 | } |
611 | 583 | ||
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 717288527c6b..ed1ef7c9cc06 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | #define DRV_VERSION "0.2" | 21 | #define DRV_VERSION "0.3" |
22 | 22 | ||
23 | #define RTC_REG_SIZE 0x2000 | 23 | #define RTC_REG_SIZE 0x2000 |
24 | #define RTC_OFFSET 0x1ff0 | 24 | #define RTC_OFFSET 0x1ff0 |
@@ -61,7 +61,6 @@ | |||
61 | struct rtc_plat_data { | 61 | struct rtc_plat_data { |
62 | struct rtc_device *rtc; | 62 | struct rtc_device *rtc; |
63 | void __iomem *ioaddr; | 63 | void __iomem *ioaddr; |
64 | resource_size_t baseaddr; | ||
65 | unsigned long last_jiffies; | 64 | unsigned long last_jiffies; |
66 | int irq; | 65 | int irq; |
67 | unsigned int irqen; | 66 | unsigned int irqen; |
@@ -69,6 +68,7 @@ struct rtc_plat_data { | |||
69 | int alrm_min; | 68 | int alrm_min; |
70 | int alrm_hour; | 69 | int alrm_hour; |
71 | int alrm_mday; | 70 | int alrm_mday; |
71 | spinlock_t lock; | ||
72 | }; | 72 | }; |
73 | 73 | ||
74 | static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) | 74 | static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -139,7 +139,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
139 | void __iomem *ioaddr = pdata->ioaddr; | 139 | void __iomem *ioaddr = pdata->ioaddr; |
140 | unsigned long flags; | 140 | unsigned long flags; |
141 | 141 | ||
142 | spin_lock_irqsave(&pdata->rtc->irq_lock, flags); | 142 | spin_lock_irqsave(&pdata->lock, flags); |
143 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | 143 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? |
144 | 0x80 : bin2bcd(pdata->alrm_mday), | 144 | 0x80 : bin2bcd(pdata->alrm_mday), |
145 | ioaddr + RTC_DATE_ALARM); | 145 | ioaddr + RTC_DATE_ALARM); |
@@ -154,7 +154,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
154 | ioaddr + RTC_SECONDS_ALARM); | 154 | ioaddr + RTC_SECONDS_ALARM); |
155 | writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); | 155 | writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); |
156 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | 156 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ |
157 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); | 157 | spin_unlock_irqrestore(&pdata->lock, flags); |
158 | } | 158 | } |
159 | 159 | ||
160 | static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 160 | static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
@@ -194,64 +194,69 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) | |||
194 | struct platform_device *pdev = dev_id; | 194 | struct platform_device *pdev = dev_id; |
195 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 195 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
196 | void __iomem *ioaddr = pdata->ioaddr; | 196 | void __iomem *ioaddr = pdata->ioaddr; |
197 | unsigned long events = RTC_IRQF; | 197 | unsigned long events = 0; |
198 | 198 | ||
199 | spin_lock(&pdata->lock); | ||
199 | /* read and clear interrupt */ | 200 | /* read and clear interrupt */ |
200 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | 201 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { |
201 | return IRQ_NONE; | 202 | events = RTC_IRQF; |
202 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | 203 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) |
203 | events |= RTC_UF; | 204 | events |= RTC_UF; |
204 | else | 205 | else |
205 | events |= RTC_AF; | 206 | events |= RTC_AF; |
206 | rtc_update_irq(pdata->rtc, 1, events); | 207 | if (likely(pdata->rtc)) |
207 | return IRQ_HANDLED; | 208 | rtc_update_irq(pdata->rtc, 1, events); |
209 | } | ||
210 | spin_unlock(&pdata->lock); | ||
211 | return events ? IRQ_HANDLED : IRQ_NONE; | ||
208 | } | 212 | } |
209 | 213 | ||
210 | static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, | 214 | static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
211 | unsigned long arg) | ||
212 | { | 215 | { |
213 | struct platform_device *pdev = to_platform_device(dev); | 216 | struct platform_device *pdev = to_platform_device(dev); |
214 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 217 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
215 | 218 | ||
216 | if (pdata->irq <= 0) | 219 | if (pdata->irq <= 0) |
217 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | 220 | return -EINVAL; |
218 | switch (cmd) { | 221 | if (enabled) |
219 | case RTC_AIE_OFF: | ||
220 | pdata->irqen &= ~RTC_AF; | ||
221 | ds1553_rtc_update_alarm(pdata); | ||
222 | break; | ||
223 | case RTC_AIE_ON: | ||
224 | pdata->irqen |= RTC_AF; | 222 | pdata->irqen |= RTC_AF; |
225 | ds1553_rtc_update_alarm(pdata); | 223 | else |
226 | break; | 224 | pdata->irqen &= ~RTC_AF; |
227 | case RTC_UIE_OFF: | 225 | ds1553_rtc_update_alarm(pdata); |
228 | pdata->irqen &= ~RTC_UF; | 226 | return 0; |
229 | ds1553_rtc_update_alarm(pdata); | 227 | } |
230 | break; | 228 | |
231 | case RTC_UIE_ON: | 229 | static int ds1553_rtc_update_irq_enable(struct device *dev, |
230 | unsigned int enabled) | ||
231 | { | ||
232 | struct platform_device *pdev = to_platform_device(dev); | ||
233 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
234 | |||
235 | if (pdata->irq <= 0) | ||
236 | return -EINVAL; | ||
237 | if (enabled) | ||
232 | pdata->irqen |= RTC_UF; | 238 | pdata->irqen |= RTC_UF; |
233 | ds1553_rtc_update_alarm(pdata); | 239 | else |
234 | break; | 240 | pdata->irqen &= ~RTC_UF; |
235 | default: | 241 | ds1553_rtc_update_alarm(pdata); |
236 | return -ENOIOCTLCMD; | ||
237 | } | ||
238 | return 0; | 242 | return 0; |
239 | } | 243 | } |
240 | 244 | ||
241 | static const struct rtc_class_ops ds1553_rtc_ops = { | 245 | static const struct rtc_class_ops ds1553_rtc_ops = { |
242 | .read_time = ds1553_rtc_read_time, | 246 | .read_time = ds1553_rtc_read_time, |
243 | .set_time = ds1553_rtc_set_time, | 247 | .set_time = ds1553_rtc_set_time, |
244 | .read_alarm = ds1553_rtc_read_alarm, | 248 | .read_alarm = ds1553_rtc_read_alarm, |
245 | .set_alarm = ds1553_rtc_set_alarm, | 249 | .set_alarm = ds1553_rtc_set_alarm, |
246 | .ioctl = ds1553_rtc_ioctl, | 250 | .alarm_irq_enable = ds1553_rtc_alarm_irq_enable, |
251 | .update_irq_enable = ds1553_rtc_update_irq_enable, | ||
247 | }; | 252 | }; |
248 | 253 | ||
249 | static ssize_t ds1553_nvram_read(struct kobject *kobj, | 254 | static ssize_t ds1553_nvram_read(struct kobject *kobj, |
250 | struct bin_attribute *bin_attr, | 255 | struct bin_attribute *bin_attr, |
251 | char *buf, loff_t pos, size_t size) | 256 | char *buf, loff_t pos, size_t size) |
252 | { | 257 | { |
253 | struct platform_device *pdev = | 258 | struct device *dev = container_of(kobj, struct device, kobj); |
254 | to_platform_device(container_of(kobj, struct device, kobj)); | 259 | struct platform_device *pdev = to_platform_device(dev); |
255 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 260 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
256 | void __iomem *ioaddr = pdata->ioaddr; | 261 | void __iomem *ioaddr = pdata->ioaddr; |
257 | ssize_t count; | 262 | ssize_t count; |
@@ -265,8 +270,8 @@ static ssize_t ds1553_nvram_write(struct kobject *kobj, | |||
265 | struct bin_attribute *bin_attr, | 270 | struct bin_attribute *bin_attr, |
266 | char *buf, loff_t pos, size_t size) | 271 | char *buf, loff_t pos, size_t size) |
267 | { | 272 | { |
268 | struct platform_device *pdev = | 273 | struct device *dev = container_of(kobj, struct device, kobj); |
269 | to_platform_device(container_of(kobj, struct device, kobj)); | 274 | struct platform_device *pdev = to_platform_device(dev); |
270 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 275 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
271 | void __iomem *ioaddr = pdata->ioaddr; | 276 | void __iomem *ioaddr = pdata->ioaddr; |
272 | ssize_t count; | 277 | ssize_t count; |
@@ -291,26 +296,23 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
291 | struct rtc_device *rtc; | 296 | struct rtc_device *rtc; |
292 | struct resource *res; | 297 | struct resource *res; |
293 | unsigned int cen, sec; | 298 | unsigned int cen, sec; |
294 | struct rtc_plat_data *pdata = NULL; | 299 | struct rtc_plat_data *pdata; |
295 | void __iomem *ioaddr = NULL; | 300 | void __iomem *ioaddr; |
296 | int ret = 0; | 301 | int ret = 0; |
297 | 302 | ||
298 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 303 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
299 | if (!res) | 304 | if (!res) |
300 | return -ENODEV; | 305 | return -ENODEV; |
301 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 306 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
302 | if (!pdata) | 307 | if (!pdata) |
303 | return -ENOMEM; | 308 | return -ENOMEM; |
304 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | 309 | if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, |
305 | ret = -EBUSY; | 310 | pdev->name)) |
306 | goto out; | 311 | return -EBUSY; |
307 | } | 312 | |
308 | pdata->baseaddr = res->start; | 313 | ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); |
309 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | 314 | if (!ioaddr) |
310 | if (!ioaddr) { | 315 | return -ENOMEM; |
311 | ret = -ENOMEM; | ||
312 | goto out; | ||
313 | } | ||
314 | pdata->ioaddr = ioaddr; | 316 | pdata->ioaddr = ioaddr; |
315 | pdata->irq = platform_get_irq(pdev, 0); | 317 | pdata->irq = platform_get_irq(pdev, 0); |
316 | 318 | ||
@@ -326,9 +328,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
326 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) | 328 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) |
327 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 329 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
328 | 330 | ||
331 | spin_lock_init(&pdata->lock); | ||
332 | pdata->last_jiffies = jiffies; | ||
333 | platform_set_drvdata(pdev, pdata); | ||
329 | if (pdata->irq > 0) { | 334 | if (pdata->irq > 0) { |
330 | writeb(0, ioaddr + RTC_INTERRUPTS); | 335 | writeb(0, ioaddr + RTC_INTERRUPTS); |
331 | if (request_irq(pdata->irq, ds1553_rtc_interrupt, | 336 | if (devm_request_irq(&pdev->dev, pdata->irq, |
337 | ds1553_rtc_interrupt, | ||
332 | IRQF_DISABLED, pdev->name, pdev) < 0) { | 338 | IRQF_DISABLED, pdev->name, pdev) < 0) { |
333 | dev_warn(&pdev->dev, "interrupt not available.\n"); | 339 | dev_warn(&pdev->dev, "interrupt not available.\n"); |
334 | pdata->irq = 0; | 340 | pdata->irq = 0; |
@@ -337,27 +343,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
337 | 343 | ||
338 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 344 | rtc = rtc_device_register(pdev->name, &pdev->dev, |
339 | &ds1553_rtc_ops, THIS_MODULE); | 345 | &ds1553_rtc_ops, THIS_MODULE); |
340 | if (IS_ERR(rtc)) { | 346 | if (IS_ERR(rtc)) |
341 | ret = PTR_ERR(rtc); | 347 | return PTR_ERR(rtc); |
342 | goto out; | ||
343 | } | ||
344 | pdata->rtc = rtc; | 348 | pdata->rtc = rtc; |
345 | pdata->last_jiffies = jiffies; | 349 | |
346 | platform_set_drvdata(pdev, pdata); | ||
347 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | 350 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); |
348 | if (ret) | 351 | if (ret) |
349 | goto out; | 352 | rtc_device_unregister(rtc); |
350 | return 0; | ||
351 | out: | ||
352 | if (pdata->rtc) | ||
353 | rtc_device_unregister(pdata->rtc); | ||
354 | if (pdata->irq > 0) | ||
355 | free_irq(pdata->irq, pdev); | ||
356 | if (ioaddr) | ||
357 | iounmap(ioaddr); | ||
358 | if (pdata->baseaddr) | ||
359 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
360 | kfree(pdata); | ||
361 | return ret; | 353 | return ret; |
362 | } | 354 | } |
363 | 355 | ||
@@ -367,13 +359,8 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev) | |||
367 | 359 | ||
368 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | 360 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); |
369 | rtc_device_unregister(pdata->rtc); | 361 | rtc_device_unregister(pdata->rtc); |
370 | if (pdata->irq > 0) { | 362 | if (pdata->irq > 0) |
371 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | 363 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); |
372 | free_irq(pdata->irq, pdev); | ||
373 | } | ||
374 | iounmap(pdata->ioaddr); | ||
375 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
376 | kfree(pdata); | ||
377 | return 0; | 364 | return 0; |
378 | } | 365 | } |
379 | 366 | ||
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 09249459e9a4..a1273360a44e 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | 23 | ||
24 | #define DRV_VERSION "0.3" | 24 | #define DRV_VERSION "0.4" |
25 | 25 | ||
26 | #define RTC_SIZE 8 | 26 | #define RTC_SIZE 8 |
27 | 27 | ||
@@ -55,7 +55,6 @@ struct rtc_plat_data { | |||
55 | void __iomem *ioaddr_rtc; | 55 | void __iomem *ioaddr_rtc; |
56 | size_t size_nvram; | 56 | size_t size_nvram; |
57 | size_t size; | 57 | size_t size; |
58 | resource_size_t baseaddr; | ||
59 | unsigned long last_jiffies; | 58 | unsigned long last_jiffies; |
60 | struct bin_attribute nvram_attr; | 59 | struct bin_attribute nvram_attr; |
61 | }; | 60 | }; |
@@ -132,8 +131,8 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj, | |||
132 | struct bin_attribute *bin_attr, | 131 | struct bin_attribute *bin_attr, |
133 | char *buf, loff_t pos, size_t size) | 132 | char *buf, loff_t pos, size_t size) |
134 | { | 133 | { |
135 | struct platform_device *pdev = | 134 | struct device *dev = container_of(kobj, struct device, kobj); |
136 | to_platform_device(container_of(kobj, struct device, kobj)); | 135 | struct platform_device *pdev = to_platform_device(dev); |
137 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 136 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
138 | void __iomem *ioaddr = pdata->ioaddr_nvram; | 137 | void __iomem *ioaddr = pdata->ioaddr_nvram; |
139 | ssize_t count; | 138 | ssize_t count; |
@@ -147,8 +146,8 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj, | |||
147 | struct bin_attribute *bin_attr, | 146 | struct bin_attribute *bin_attr, |
148 | char *buf, loff_t pos, size_t size) | 147 | char *buf, loff_t pos, size_t size) |
149 | { | 148 | { |
150 | struct platform_device *pdev = | 149 | struct device *dev = container_of(kobj, struct device, kobj); |
151 | to_platform_device(container_of(kobj, struct device, kobj)); | 150 | struct platform_device *pdev = to_platform_device(dev); |
152 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 151 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
153 | void __iomem *ioaddr = pdata->ioaddr_nvram; | 152 | void __iomem *ioaddr = pdata->ioaddr_nvram; |
154 | ssize_t count; | 153 | ssize_t count; |
@@ -163,27 +162,24 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) | |||
163 | struct rtc_device *rtc; | 162 | struct rtc_device *rtc; |
164 | struct resource *res; | 163 | struct resource *res; |
165 | unsigned int cen, sec; | 164 | unsigned int cen, sec; |
166 | struct rtc_plat_data *pdata = NULL; | 165 | struct rtc_plat_data *pdata; |
167 | void __iomem *ioaddr = NULL; | 166 | void __iomem *ioaddr; |
168 | int ret = 0; | 167 | int ret = 0; |
169 | 168 | ||
170 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
171 | if (!res) | 170 | if (!res) |
172 | return -ENODEV; | 171 | return -ENODEV; |
173 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 172 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
174 | if (!pdata) | 173 | if (!pdata) |
175 | return -ENOMEM; | 174 | return -ENOMEM; |
176 | pdata->size = res->end - res->start + 1; | 175 | pdata->size = res->end - res->start + 1; |
177 | if (!request_mem_region(res->start, pdata->size, pdev->name)) { | 176 | if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, |
178 | ret = -EBUSY; | 177 | pdev->name)) |
179 | goto out; | 178 | return -EBUSY; |
180 | } | 179 | ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size); |
181 | pdata->baseaddr = res->start; | 180 | if (!ioaddr) |
182 | ioaddr = ioremap(pdata->baseaddr, pdata->size); | 181 | return -ENOMEM; |
183 | if (!ioaddr) { | 182 | |
184 | ret = -ENOMEM; | ||
185 | goto out; | ||
186 | } | ||
187 | pdata->ioaddr_nvram = ioaddr; | 183 | pdata->ioaddr_nvram = ioaddr; |
188 | pdata->size_nvram = pdata->size - RTC_SIZE; | 184 | pdata->size_nvram = pdata->size - RTC_SIZE; |
189 | pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; | 185 | pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; |
@@ -207,31 +203,19 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) | |||
207 | if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)) | 203 | if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)) |
208 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 204 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
209 | 205 | ||
206 | pdata->last_jiffies = jiffies; | ||
207 | platform_set_drvdata(pdev, pdata); | ||
210 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 208 | rtc = rtc_device_register(pdev->name, &pdev->dev, |
211 | &ds1742_rtc_ops, THIS_MODULE); | 209 | &ds1742_rtc_ops, THIS_MODULE); |
212 | if (IS_ERR(rtc)) { | 210 | if (IS_ERR(rtc)) |
213 | ret = PTR_ERR(rtc); | 211 | return PTR_ERR(rtc); |
214 | goto out; | ||
215 | } | ||
216 | pdata->rtc = rtc; | 212 | pdata->rtc = rtc; |
217 | pdata->last_jiffies = jiffies; | ||
218 | platform_set_drvdata(pdev, pdata); | ||
219 | 213 | ||
220 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); | 214 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); |
221 | if (ret) { | 215 | if (ret) { |
222 | dev_err(&pdev->dev, "creating nvram file in sysfs failed\n"); | 216 | dev_err(&pdev->dev, "creating nvram file in sysfs failed\n"); |
223 | goto out; | 217 | rtc_device_unregister(rtc); |
224 | } | 218 | } |
225 | |||
226 | return 0; | ||
227 | out: | ||
228 | if (pdata->rtc) | ||
229 | rtc_device_unregister(pdata->rtc); | ||
230 | if (pdata->ioaddr_nvram) | ||
231 | iounmap(pdata->ioaddr_nvram); | ||
232 | if (pdata->baseaddr) | ||
233 | release_mem_region(pdata->baseaddr, pdata->size); | ||
234 | kfree(pdata); | ||
235 | return ret; | 219 | return ret; |
236 | } | 220 | } |
237 | 221 | ||
@@ -241,9 +225,6 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev) | |||
241 | 225 | ||
242 | sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); | 226 | sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); |
243 | rtc_device_unregister(pdata->rtc); | 227 | rtc_device_unregister(pdata->rtc); |
244 | iounmap(pdata->ioaddr_nvram); | ||
245 | release_mem_region(pdata->baseaddr, pdata->size); | ||
246 | kfree(pdata); | ||
247 | return 0; | 228 | return 0; |
248 | } | 229 | } |
249 | 230 | ||
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 0b2197559940..8cb5b8959e5b 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c | |||
@@ -142,7 +142,6 @@ static const struct rtc_class_ops m48t35_ops = { | |||
142 | 142 | ||
143 | static int __devinit m48t35_probe(struct platform_device *pdev) | 143 | static int __devinit m48t35_probe(struct platform_device *pdev) |
144 | { | 144 | { |
145 | struct rtc_device *rtc; | ||
146 | struct resource *res; | 145 | struct resource *res; |
147 | struct m48t35_priv *priv; | 146 | struct m48t35_priv *priv; |
148 | int ret = 0; | 147 | int ret = 0; |
@@ -171,20 +170,21 @@ static int __devinit m48t35_probe(struct platform_device *pdev) | |||
171 | ret = -ENOMEM; | 170 | ret = -ENOMEM; |
172 | goto out; | 171 | goto out; |
173 | } | 172 | } |
173 | |||
174 | spin_lock_init(&priv->lock); | 174 | spin_lock_init(&priv->lock); |
175 | rtc = rtc_device_register("m48t35", &pdev->dev, | 175 | |
176 | platform_set_drvdata(pdev, priv); | ||
177 | |||
178 | priv->rtc = rtc_device_register("m48t35", &pdev->dev, | ||
176 | &m48t35_ops, THIS_MODULE); | 179 | &m48t35_ops, THIS_MODULE); |
177 | if (IS_ERR(rtc)) { | 180 | if (IS_ERR(priv->rtc)) { |
178 | ret = PTR_ERR(rtc); | 181 | ret = PTR_ERR(priv->rtc); |
179 | goto out; | 182 | goto out; |
180 | } | 183 | } |
181 | priv->rtc = rtc; | 184 | |
182 | platform_set_drvdata(pdev, priv); | ||
183 | return 0; | 185 | return 0; |
184 | 186 | ||
185 | out: | 187 | out: |
186 | if (priv->rtc) | ||
187 | rtc_device_unregister(priv->rtc); | ||
188 | if (priv->reg) | 188 | if (priv->reg) |
189 | iounmap(priv->reg); | 189 | iounmap(priv->reg); |
190 | if (priv->baseaddr) | 190 | if (priv->baseaddr) |
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 33921a6b1707..ede43b846859 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c | |||
@@ -481,6 +481,9 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
481 | goto out; | 481 | goto out; |
482 | } | 482 | } |
483 | 483 | ||
484 | spin_lock_init(&m48t59->lock); | ||
485 | platform_set_drvdata(pdev, m48t59); | ||
486 | |||
484 | m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); | 487 | m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); |
485 | if (IS_ERR(m48t59->rtc)) { | 488 | if (IS_ERR(m48t59->rtc)) { |
486 | ret = PTR_ERR(m48t59->rtc); | 489 | ret = PTR_ERR(m48t59->rtc); |
@@ -490,16 +493,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
490 | m48t59_nvram_attr.size = pdata->offset; | 493 | m48t59_nvram_attr.size = pdata->offset; |
491 | 494 | ||
492 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | 495 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); |
493 | if (ret) | 496 | if (ret) { |
497 | rtc_device_unregister(m48t59->rtc); | ||
494 | goto out; | 498 | goto out; |
499 | } | ||
495 | 500 | ||
496 | spin_lock_init(&m48t59->lock); | ||
497 | platform_set_drvdata(pdev, m48t59); | ||
498 | return 0; | 501 | return 0; |
499 | 502 | ||
500 | out: | 503 | out: |
501 | if (!IS_ERR(m48t59->rtc)) | ||
502 | rtc_device_unregister(m48t59->rtc); | ||
503 | if (m48t59->irq != NO_IRQ) | 504 | if (m48t59->irq != NO_IRQ) |
504 | free_irq(m48t59->irq, &pdev->dev); | 505 | free_irq(m48t59->irq, &pdev->dev); |
505 | if (m48t59->ioaddr) | 506 | if (m48t59->ioaddr) |
diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c new file mode 100644 index 000000000000..850f983c039c --- /dev/null +++ b/drivers/rtc/rtc-mc13783.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Real Time Clock driver for Freescale MC13783 PMIC | ||
3 | * | ||
4 | * (C) 2009 Sascha Hauer, Pengutronix | ||
5 | * (C) 2009 Uwe Kleine-Koenig, Pengutronix | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/mfd/mc13783.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/rtc.h> | ||
17 | |||
18 | #define DRIVER_NAME "mc13783-rtc" | ||
19 | |||
20 | #define MC13783_RTCTOD 20 | ||
21 | #define MC13783_RTCTODA 21 | ||
22 | #define MC13783_RTCDAY 22 | ||
23 | #define MC13783_RTCDAYA 23 | ||
24 | |||
25 | struct mc13783_rtc { | ||
26 | struct rtc_device *rtc; | ||
27 | struct mc13783 *mc13783; | ||
28 | int valid; | ||
29 | }; | ||
30 | |||
31 | static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
32 | { | ||
33 | struct mc13783_rtc *priv = dev_get_drvdata(dev); | ||
34 | unsigned int seconds, days1, days2; | ||
35 | unsigned long s1970; | ||
36 | int ret; | ||
37 | |||
38 | mc13783_lock(priv->mc13783); | ||
39 | |||
40 | if (!priv->valid) { | ||
41 | ret = -ENODATA; | ||
42 | goto out; | ||
43 | } | ||
44 | |||
45 | ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1); | ||
46 | if (unlikely(ret)) | ||
47 | goto out; | ||
48 | |||
49 | ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds); | ||
50 | if (unlikely(ret)) | ||
51 | goto out; | ||
52 | |||
53 | ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2); | ||
54 | out: | ||
55 | mc13783_unlock(priv->mc13783); | ||
56 | |||
57 | if (ret) | ||
58 | return ret; | ||
59 | |||
60 | if (days2 == days1 + 1) { | ||
61 | if (seconds >= 86400 / 2) | ||
62 | days2 = days1; | ||
63 | else | ||
64 | days1 = days2; | ||
65 | } | ||
66 | |||
67 | if (days1 != days2) | ||
68 | return -EIO; | ||
69 | |||
70 | s1970 = days1 * 86400 + seconds; | ||
71 | |||
72 | rtc_time_to_tm(s1970, tm); | ||
73 | |||
74 | return rtc_valid_tm(tm); | ||
75 | } | ||
76 | |||
77 | static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
78 | { | ||
79 | struct mc13783_rtc *priv = dev_get_drvdata(dev); | ||
80 | unsigned int seconds, days; | ||
81 | int ret; | ||
82 | |||
83 | seconds = secs % 86400; | ||
84 | days = secs / 86400; | ||
85 | |||
86 | mc13783_lock(priv->mc13783); | ||
87 | |||
88 | /* | ||
89 | * first write seconds=0 to prevent a day switch between writing days | ||
90 | * and seconds below | ||
91 | */ | ||
92 | ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0); | ||
93 | if (unlikely(ret)) | ||
94 | goto out; | ||
95 | |||
96 | ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days); | ||
97 | if (unlikely(ret)) | ||
98 | goto out; | ||
99 | |||
100 | ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds); | ||
101 | if (unlikely(ret)) | ||
102 | goto out; | ||
103 | |||
104 | ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST); | ||
105 | if (unlikely(ret)) | ||
106 | goto out; | ||
107 | |||
108 | ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST); | ||
109 | out: | ||
110 | priv->valid = !ret; | ||
111 | |||
112 | mc13783_unlock(priv->mc13783); | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) | ||
118 | { | ||
119 | struct mc13783_rtc *priv = dev; | ||
120 | struct mc13783 *mc13783 = priv->mc13783; | ||
121 | |||
122 | dev_dbg(&priv->rtc->dev, "1HZ\n"); | ||
123 | |||
124 | rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); | ||
125 | |||
126 | mc13783_ackirq(mc13783, irq); | ||
127 | |||
128 | return IRQ_HANDLED; | ||
129 | } | ||
130 | |||
131 | static int mc13783_rtc_update_irq_enable(struct device *dev, | ||
132 | unsigned int enabled) | ||
133 | { | ||
134 | struct mc13783_rtc *priv = dev_get_drvdata(dev); | ||
135 | int ret = -ENODATA; | ||
136 | |||
137 | mc13783_lock(priv->mc13783); | ||
138 | if (!priv->valid) | ||
139 | goto out; | ||
140 | |||
141 | ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783, | ||
142 | MC13783_IRQ_1HZ); | ||
143 | out: | ||
144 | mc13783_unlock(priv->mc13783); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static const struct rtc_class_ops mc13783_rtc_ops = { | ||
150 | .read_time = mc13783_rtc_read_time, | ||
151 | .set_mmss = mc13783_rtc_set_mmss, | ||
152 | .update_irq_enable = mc13783_rtc_update_irq_enable, | ||
153 | }; | ||
154 | |||
155 | static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) | ||
156 | { | ||
157 | struct mc13783_rtc *priv = dev; | ||
158 | struct mc13783 *mc13783 = priv->mc13783; | ||
159 | |||
160 | dev_dbg(&priv->rtc->dev, "RTCRST\n"); | ||
161 | priv->valid = 0; | ||
162 | |||
163 | mc13783_mask(mc13783, irq); | ||
164 | |||
165 | return IRQ_HANDLED; | ||
166 | } | ||
167 | |||
168 | static int __devinit mc13783_rtc_probe(struct platform_device *pdev) | ||
169 | { | ||
170 | int ret; | ||
171 | struct mc13783_rtc *priv; | ||
172 | |||
173 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
174 | if (!priv) | ||
175 | return -ENOMEM; | ||
176 | |||
177 | priv->mc13783 = dev_get_drvdata(pdev->dev.parent); | ||
178 | platform_set_drvdata(pdev, priv); | ||
179 | |||
180 | priv->valid = 1; | ||
181 | |||
182 | mc13783_lock(priv->mc13783); | ||
183 | |||
184 | ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, | ||
185 | mc13783_rtc_reset_handler, DRIVER_NAME, priv); | ||
186 | if (ret) | ||
187 | goto err_reset_irq_request; | ||
188 | |||
189 | ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, | ||
190 | mc13783_rtc_update_handler, DRIVER_NAME, priv); | ||
191 | if (ret) | ||
192 | goto err_update_irq_request; | ||
193 | |||
194 | mc13783_unlock(priv->mc13783); | ||
195 | |||
196 | priv->rtc = rtc_device_register(pdev->name, | ||
197 | &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); | ||
198 | |||
199 | if (IS_ERR(priv->rtc)) { | ||
200 | ret = PTR_ERR(priv->rtc); | ||
201 | |||
202 | mc13783_lock(priv->mc13783); | ||
203 | |||
204 | mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); | ||
205 | err_update_irq_request: | ||
206 | |||
207 | mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); | ||
208 | err_reset_irq_request: | ||
209 | |||
210 | mc13783_unlock(priv->mc13783); | ||
211 | |||
212 | platform_set_drvdata(pdev, NULL); | ||
213 | kfree(priv); | ||
214 | } | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int __devexit mc13783_rtc_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | struct mc13783_rtc *priv = platform_get_drvdata(pdev); | ||
222 | |||
223 | rtc_device_unregister(priv->rtc); | ||
224 | |||
225 | mc13783_lock(priv->mc13783); | ||
226 | |||
227 | mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); | ||
228 | mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); | ||
229 | |||
230 | mc13783_unlock(priv->mc13783); | ||
231 | |||
232 | platform_set_drvdata(pdev, NULL); | ||
233 | |||
234 | kfree(priv); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct platform_driver mc13783_rtc_driver = { | ||
240 | .remove = __devexit_p(mc13783_rtc_remove), | ||
241 | .driver = { | ||
242 | .name = DRIVER_NAME, | ||
243 | .owner = THIS_MODULE, | ||
244 | }, | ||
245 | }; | ||
246 | |||
247 | static int __init mc13783_rtc_init(void) | ||
248 | { | ||
249 | return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe); | ||
250 | } | ||
251 | module_init(mc13783_rtc_init); | ||
252 | |||
253 | static void __exit mc13783_rtc_exit(void) | ||
254 | { | ||
255 | platform_driver_unregister(&mc13783_rtc_driver); | ||
256 | } | ||
257 | module_exit(mc13783_rtc_exit); | ||
258 | |||
259 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | ||
260 | MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC"); | ||
261 | MODULE_LICENSE("GPL v2"); | ||
262 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index e0263d2005ee..dc052ce6e63a 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c | |||
@@ -27,10 +27,17 @@ | |||
27 | #define RTC_MONTH_OFFS 8 | 27 | #define RTC_MONTH_OFFS 8 |
28 | #define RTC_YEAR_OFFS 16 | 28 | #define RTC_YEAR_OFFS 16 |
29 | 29 | ||
30 | #define RTC_ALARM_TIME_REG_OFFS 8 | ||
31 | #define RTC_ALARM_DATE_REG_OFFS 0xc | ||
32 | #define RTC_ALARM_VALID (1 << 7) | ||
33 | |||
34 | #define RTC_ALARM_INTERRUPT_MASK_REG_OFFS 0x10 | ||
35 | #define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS 0x14 | ||
30 | 36 | ||
31 | struct rtc_plat_data { | 37 | struct rtc_plat_data { |
32 | struct rtc_device *rtc; | 38 | struct rtc_device *rtc; |
33 | void __iomem *ioaddr; | 39 | void __iomem *ioaddr; |
40 | int irq; | ||
34 | }; | 41 | }; |
35 | 42 | ||
36 | static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) | 43 | static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -84,12 +91,134 @@ static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
84 | return rtc_valid_tm(tm); | 91 | return rtc_valid_tm(tm); |
85 | } | 92 | } |
86 | 93 | ||
94 | static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
95 | { | ||
96 | struct rtc_plat_data *pdata = dev_get_drvdata(dev); | ||
97 | void __iomem *ioaddr = pdata->ioaddr; | ||
98 | u32 rtc_time, rtc_date; | ||
99 | unsigned int year, month, day, hour, minute, second, wday; | ||
100 | |||
101 | rtc_time = readl(ioaddr + RTC_ALARM_TIME_REG_OFFS); | ||
102 | rtc_date = readl(ioaddr + RTC_ALARM_DATE_REG_OFFS); | ||
103 | |||
104 | second = rtc_time & 0x7f; | ||
105 | minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f; | ||
106 | hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */ | ||
107 | wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7; | ||
108 | |||
109 | day = rtc_date & 0x3f; | ||
110 | month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f; | ||
111 | year = (rtc_date >> RTC_YEAR_OFFS) & 0xff; | ||
112 | |||
113 | alm->time.tm_sec = bcd2bin(second); | ||
114 | alm->time.tm_min = bcd2bin(minute); | ||
115 | alm->time.tm_hour = bcd2bin(hour); | ||
116 | alm->time.tm_mday = bcd2bin(day); | ||
117 | alm->time.tm_wday = bcd2bin(wday); | ||
118 | alm->time.tm_mon = bcd2bin(month) - 1; | ||
119 | /* hw counts from year 2000, but tm_year is relative to 1900 */ | ||
120 | alm->time.tm_year = bcd2bin(year) + 100; | ||
121 | |||
122 | if (rtc_valid_tm(&alm->time) < 0) { | ||
123 | dev_err(dev, "retrieved alarm date/time is not valid.\n"); | ||
124 | rtc_time_to_tm(0, &alm->time); | ||
125 | } | ||
126 | |||
127 | alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
132 | { | ||
133 | struct rtc_plat_data *pdata = dev_get_drvdata(dev); | ||
134 | void __iomem *ioaddr = pdata->ioaddr; | ||
135 | u32 rtc_reg = 0; | ||
136 | |||
137 | if (alm->time.tm_sec >= 0) | ||
138 | rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_sec)) | ||
139 | << RTC_SECONDS_OFFS; | ||
140 | if (alm->time.tm_min >= 0) | ||
141 | rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_min)) | ||
142 | << RTC_MINUTES_OFFS; | ||
143 | if (alm->time.tm_hour >= 0) | ||
144 | rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_hour)) | ||
145 | << RTC_HOURS_OFFS; | ||
146 | |||
147 | writel(rtc_reg, ioaddr + RTC_ALARM_TIME_REG_OFFS); | ||
148 | |||
149 | if (alm->time.tm_mday >= 0) | ||
150 | rtc_reg = (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mday)) | ||
151 | << RTC_MDAY_OFFS; | ||
152 | else | ||
153 | rtc_reg = 0; | ||
154 | |||
155 | if (alm->time.tm_mon >= 0) | ||
156 | rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mon + 1)) | ||
157 | << RTC_MONTH_OFFS; | ||
158 | |||
159 | if (alm->time.tm_year >= 0) | ||
160 | rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year % 100)) | ||
161 | << RTC_YEAR_OFFS; | ||
162 | |||
163 | writel(rtc_reg, ioaddr + RTC_ALARM_DATE_REG_OFFS); | ||
164 | writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); | ||
165 | writel(alm->enabled ? 1 : 0, | ||
166 | ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int mv_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
172 | unsigned long arg) | ||
173 | { | ||
174 | struct platform_device *pdev = to_platform_device(dev); | ||
175 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
176 | void __iomem *ioaddr = pdata->ioaddr; | ||
177 | |||
178 | if (pdata->irq < 0) | ||
179 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | ||
180 | switch (cmd) { | ||
181 | case RTC_AIE_OFF: | ||
182 | writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); | ||
183 | break; | ||
184 | case RTC_AIE_ON: | ||
185 | writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); | ||
186 | break; | ||
187 | default: | ||
188 | return -ENOIOCTLCMD; | ||
189 | } | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static irqreturn_t mv_rtc_interrupt(int irq, void *data) | ||
194 | { | ||
195 | struct rtc_plat_data *pdata = data; | ||
196 | void __iomem *ioaddr = pdata->ioaddr; | ||
197 | |||
198 | /* alarm irq? */ | ||
199 | if (!readl(ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS)) | ||
200 | return IRQ_NONE; | ||
201 | |||
202 | /* clear interrupt */ | ||
203 | writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); | ||
204 | rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); | ||
205 | return IRQ_HANDLED; | ||
206 | } | ||
207 | |||
87 | static const struct rtc_class_ops mv_rtc_ops = { | 208 | static const struct rtc_class_ops mv_rtc_ops = { |
88 | .read_time = mv_rtc_read_time, | 209 | .read_time = mv_rtc_read_time, |
89 | .set_time = mv_rtc_set_time, | 210 | .set_time = mv_rtc_set_time, |
90 | }; | 211 | }; |
91 | 212 | ||
92 | static int __init mv_rtc_probe(struct platform_device *pdev) | 213 | static const struct rtc_class_ops mv_rtc_alarm_ops = { |
214 | .read_time = mv_rtc_read_time, | ||
215 | .set_time = mv_rtc_set_time, | ||
216 | .read_alarm = mv_rtc_read_alarm, | ||
217 | .set_alarm = mv_rtc_set_alarm, | ||
218 | .ioctl = mv_rtc_ioctl, | ||
219 | }; | ||
220 | |||
221 | static int __devinit mv_rtc_probe(struct platform_device *pdev) | ||
93 | { | 222 | { |
94 | struct resource *res; | 223 | struct resource *res; |
95 | struct rtc_plat_data *pdata; | 224 | struct rtc_plat_data *pdata; |
@@ -130,12 +259,31 @@ static int __init mv_rtc_probe(struct platform_device *pdev) | |||
130 | } | 259 | } |
131 | } | 260 | } |
132 | 261 | ||
262 | pdata->irq = platform_get_irq(pdev, 0); | ||
263 | |||
133 | platform_set_drvdata(pdev, pdata); | 264 | platform_set_drvdata(pdev, pdata); |
134 | pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, | 265 | |
135 | &mv_rtc_ops, THIS_MODULE); | 266 | if (pdata->irq >= 0) { |
267 | device_init_wakeup(&pdev->dev, 1); | ||
268 | pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
269 | &mv_rtc_alarm_ops, | ||
270 | THIS_MODULE); | ||
271 | } else | ||
272 | pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
273 | &mv_rtc_ops, THIS_MODULE); | ||
136 | if (IS_ERR(pdata->rtc)) | 274 | if (IS_ERR(pdata->rtc)) |
137 | return PTR_ERR(pdata->rtc); | 275 | return PTR_ERR(pdata->rtc); |
138 | 276 | ||
277 | if (pdata->irq >= 0) { | ||
278 | writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); | ||
279 | if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt, | ||
280 | IRQF_DISABLED | IRQF_SHARED, | ||
281 | pdev->name, pdata) < 0) { | ||
282 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
283 | pdata->irq = -1; | ||
284 | } | ||
285 | } | ||
286 | |||
139 | return 0; | 287 | return 0; |
140 | } | 288 | } |
141 | 289 | ||
@@ -143,6 +291,9 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) | |||
143 | { | 291 | { |
144 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 292 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
145 | 293 | ||
294 | if (pdata->irq >= 0) | ||
295 | device_init_wakeup(&pdev->dev, 0); | ||
296 | |||
146 | rtc_device_unregister(pdata->rtc); | 297 | rtc_device_unregister(pdata->rtc); |
147 | return 0; | 298 | return 0; |
148 | } | 299 | } |
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c new file mode 100644 index 000000000000..bf59c9c586b2 --- /dev/null +++ b/drivers/rtc/rtc-nuc900.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/bcd.h> | ||
19 | |||
20 | /* RTC Control Registers */ | ||
21 | #define REG_RTC_INIR 0x00 | ||
22 | #define REG_RTC_AER 0x04 | ||
23 | #define REG_RTC_FCR 0x08 | ||
24 | #define REG_RTC_TLR 0x0C | ||
25 | #define REG_RTC_CLR 0x10 | ||
26 | #define REG_RTC_TSSR 0x14 | ||
27 | #define REG_RTC_DWR 0x18 | ||
28 | #define REG_RTC_TAR 0x1C | ||
29 | #define REG_RTC_CAR 0x20 | ||
30 | #define REG_RTC_LIR 0x24 | ||
31 | #define REG_RTC_RIER 0x28 | ||
32 | #define REG_RTC_RIIR 0x2C | ||
33 | #define REG_RTC_TTR 0x30 | ||
34 | |||
35 | #define RTCSET 0x01 | ||
36 | #define AERRWENB 0x10000 | ||
37 | #define INIRRESET 0xa5eb1357 | ||
38 | #define AERPOWERON 0xA965 | ||
39 | #define AERPOWEROFF 0x0000 | ||
40 | #define LEAPYEAR 0x0001 | ||
41 | #define TICKENB 0x80 | ||
42 | #define TICKINTENB 0x0002 | ||
43 | #define ALARMINTENB 0x0001 | ||
44 | #define MODE24 0x0001 | ||
45 | |||
46 | struct nuc900_rtc { | ||
47 | int irq_num; | ||
48 | void __iomem *rtc_reg; | ||
49 | struct rtc_device *rtcdev; | ||
50 | }; | ||
51 | |||
52 | struct nuc900_bcd_time { | ||
53 | int bcd_sec; | ||
54 | int bcd_min; | ||
55 | int bcd_hour; | ||
56 | int bcd_mday; | ||
57 | int bcd_mon; | ||
58 | int bcd_year; | ||
59 | }; | ||
60 | |||
61 | static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc) | ||
62 | { | ||
63 | struct nuc900_rtc *rtc = _rtc; | ||
64 | unsigned long events = 0, rtc_irq; | ||
65 | |||
66 | rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR); | ||
67 | |||
68 | if (rtc_irq & ALARMINTENB) { | ||
69 | rtc_irq &= ~ALARMINTENB; | ||
70 | __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); | ||
71 | events |= RTC_AF | RTC_IRQF; | ||
72 | } | ||
73 | |||
74 | if (rtc_irq & TICKINTENB) { | ||
75 | rtc_irq &= ~TICKINTENB; | ||
76 | __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); | ||
77 | events |= RTC_UF | RTC_IRQF; | ||
78 | } | ||
79 | |||
80 | rtc_update_irq(rtc->rtcdev, 1, events); | ||
81 | |||
82 | return IRQ_HANDLED; | ||
83 | } | ||
84 | |||
85 | static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) | ||
86 | { | ||
87 | unsigned int i; | ||
88 | __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); | ||
89 | |||
90 | mdelay(10); | ||
91 | |||
92 | __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); | ||
93 | |||
94 | for (i = 0; i < 1000; i++) { | ||
95 | if (__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | if ((__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) == 0x0) | ||
100 | return ERR_PTR(-ENODEV); | ||
101 | |||
102 | return ERR_PTR(-EPERM); | ||
103 | } | ||
104 | |||
105 | static void nuc900_rtc_bcd2bin(unsigned int timereg, | ||
106 | unsigned int calreg, struct rtc_time *tm) | ||
107 | { | ||
108 | tm->tm_mday = bcd2bin(calreg >> 0); | ||
109 | tm->tm_mon = bcd2bin(calreg >> 8); | ||
110 | tm->tm_year = bcd2bin(calreg >> 16) + 100; | ||
111 | |||
112 | tm->tm_sec = bcd2bin(timereg >> 0); | ||
113 | tm->tm_min = bcd2bin(timereg >> 8); | ||
114 | tm->tm_hour = bcd2bin(timereg >> 16); | ||
115 | |||
116 | rtc_valid_tm(tm); | ||
117 | } | ||
118 | |||
119 | static void nuc900_rtc_bin2bcd(struct rtc_time *settm, | ||
120 | struct nuc900_bcd_time *gettm) | ||
121 | { | ||
122 | gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; | ||
123 | gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8; | ||
124 | gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; | ||
125 | |||
126 | gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0; | ||
127 | gettm->bcd_min = bin2bcd(settm->tm_min) << 8; | ||
128 | gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16; | ||
129 | } | ||
130 | |||
131 | static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled) | ||
132 | { | ||
133 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
134 | |||
135 | if (enabled) | ||
136 | __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| | ||
137 | (TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); | ||
138 | else | ||
139 | __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& | ||
140 | (~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
146 | { | ||
147 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
148 | |||
149 | if (enabled) | ||
150 | __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| | ||
151 | (ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); | ||
152 | else | ||
153 | __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& | ||
154 | (~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
160 | { | ||
161 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
162 | unsigned int timeval, clrval; | ||
163 | |||
164 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); | ||
165 | clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR); | ||
166 | |||
167 | nuc900_rtc_bcd2bin(timeval, clrval, tm); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
173 | { | ||
174 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
175 | struct nuc900_bcd_time gettm; | ||
176 | unsigned long val; | ||
177 | int *err; | ||
178 | |||
179 | nuc900_rtc_bin2bcd(tm, &gettm); | ||
180 | |||
181 | err = check_rtc_access_enable(rtc); | ||
182 | if (IS_ERR(err)) | ||
183 | return PTR_ERR(err); | ||
184 | |||
185 | val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year; | ||
186 | __raw_writel(val, rtc->rtc_reg + REG_RTC_CLR); | ||
187 | |||
188 | val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour; | ||
189 | __raw_writel(val, rtc->rtc_reg + REG_RTC_TLR); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
195 | { | ||
196 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
197 | unsigned int timeval, carval; | ||
198 | |||
199 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); | ||
200 | carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR); | ||
201 | |||
202 | nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
208 | { | ||
209 | struct nuc900_rtc *rtc = dev_get_drvdata(dev); | ||
210 | struct nuc900_bcd_time tm; | ||
211 | unsigned long val; | ||
212 | int *err; | ||
213 | |||
214 | nuc900_rtc_bin2bcd(&alrm->time, &tm); | ||
215 | |||
216 | err = check_rtc_access_enable(rtc); | ||
217 | if (IS_ERR(err)) | ||
218 | return PTR_ERR(err); | ||
219 | |||
220 | val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year; | ||
221 | __raw_writel(val, rtc->rtc_reg + REG_RTC_CAR); | ||
222 | |||
223 | val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour; | ||
224 | __raw_writel(val, rtc->rtc_reg + REG_RTC_TAR); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static struct rtc_class_ops nuc900_rtc_ops = { | ||
230 | .read_time = nuc900_rtc_read_time, | ||
231 | .set_time = nuc900_rtc_set_time, | ||
232 | .read_alarm = nuc900_rtc_read_alarm, | ||
233 | .set_alarm = nuc900_rtc_set_alarm, | ||
234 | .alarm_irq_enable = nuc900_alarm_irq_enable, | ||
235 | .update_irq_enable = nuc900_update_irq_enable, | ||
236 | }; | ||
237 | |||
238 | static int __devinit nuc900_rtc_probe(struct platform_device *pdev) | ||
239 | { | ||
240 | struct resource *res; | ||
241 | struct nuc900_rtc *nuc900_rtc; | ||
242 | int err = 0; | ||
243 | |||
244 | nuc900_rtc = kzalloc(sizeof(struct nuc900_rtc), GFP_KERNEL); | ||
245 | if (!nuc900_rtc) { | ||
246 | dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n"); | ||
247 | return -ENOMEM; | ||
248 | } | ||
249 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
250 | if (!res) { | ||
251 | dev_err(&pdev->dev, "platform_get_resource failed\n"); | ||
252 | err = -ENXIO; | ||
253 | goto fail1; | ||
254 | } | ||
255 | |||
256 | if (!request_mem_region(res->start, resource_size(res), | ||
257 | pdev->name)) { | ||
258 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
259 | err = -EBUSY; | ||
260 | goto fail1; | ||
261 | } | ||
262 | |||
263 | nuc900_rtc->rtc_reg = ioremap(res->start, resource_size(res)); | ||
264 | if (!nuc900_rtc->rtc_reg) { | ||
265 | dev_err(&pdev->dev, "ioremap rtc_reg failed\n"); | ||
266 | err = -ENOMEM; | ||
267 | goto fail2; | ||
268 | } | ||
269 | |||
270 | nuc900_rtc->irq_num = platform_get_irq(pdev, 0); | ||
271 | if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt, | ||
272 | IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) { | ||
273 | dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); | ||
274 | err = -EBUSY; | ||
275 | goto fail3; | ||
276 | } | ||
277 | |||
278 | nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, | ||
279 | &nuc900_rtc_ops, THIS_MODULE); | ||
280 | if (IS_ERR(nuc900_rtc->rtcdev)) { | ||
281 | dev_err(&pdev->dev, "rtc device register faild\n"); | ||
282 | err = PTR_ERR(nuc900_rtc->rtcdev); | ||
283 | goto fail4; | ||
284 | } | ||
285 | |||
286 | platform_set_drvdata(pdev, nuc900_rtc); | ||
287 | __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, | ||
288 | nuc900_rtc->rtc_reg + REG_RTC_TSSR); | ||
289 | |||
290 | return 0; | ||
291 | |||
292 | fail4: free_irq(nuc900_rtc->irq_num, nuc900_rtc); | ||
293 | fail3: iounmap(nuc900_rtc->rtc_reg); | ||
294 | fail2: release_mem_region(res->start, resource_size(res)); | ||
295 | fail1: kfree(nuc900_rtc); | ||
296 | return err; | ||
297 | } | ||
298 | |||
299 | static int __devexit nuc900_rtc_remove(struct platform_device *pdev) | ||
300 | { | ||
301 | struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); | ||
302 | struct resource *res; | ||
303 | |||
304 | rtc_device_unregister(nuc900_rtc->rtcdev); | ||
305 | free_irq(nuc900_rtc->irq_num, nuc900_rtc); | ||
306 | iounmap(nuc900_rtc->rtc_reg); | ||
307 | |||
308 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
309 | release_mem_region(res->start, resource_size(res)); | ||
310 | |||
311 | kfree(nuc900_rtc); | ||
312 | |||
313 | platform_set_drvdata(pdev, NULL); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static struct platform_driver nuc900_rtc_driver = { | ||
319 | .remove = __devexit_p(nuc900_rtc_remove), | ||
320 | .driver = { | ||
321 | .name = "nuc900-rtc", | ||
322 | .owner = THIS_MODULE, | ||
323 | }, | ||
324 | }; | ||
325 | |||
326 | static int __init nuc900_rtc_init(void) | ||
327 | { | ||
328 | return platform_driver_probe(&nuc900_rtc_driver, nuc900_rtc_probe); | ||
329 | } | ||
330 | |||
331 | static void __exit nuc900_rtc_exit(void) | ||
332 | { | ||
333 | platform_driver_unregister(&nuc900_rtc_driver); | ||
334 | } | ||
335 | |||
336 | module_init(nuc900_rtc_init); | ||
337 | module_exit(nuc900_rtc_exit); | ||
338 | |||
339 | MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); | ||
340 | MODULE_DESCRIPTION("nuc910/nuc920 RTC driver"); | ||
341 | MODULE_LICENSE("GPL"); | ||
342 | MODULE_ALIAS("platform:nuc900-rtc"); | ||
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0587d53987fe..64d9727b7229 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -87,9 +87,10 @@ | |||
87 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) | 87 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) |
88 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) | 88 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) |
89 | 89 | ||
90 | static void __iomem *rtc_base; | ||
90 | 91 | ||
91 | #define rtc_read(addr) omap_readb(OMAP_RTC_BASE + (addr)) | 92 | #define rtc_read(addr) __raw_readb(rtc_base + (addr)) |
92 | #define rtc_write(val, addr) omap_writeb(val, OMAP_RTC_BASE + (addr)) | 93 | #define rtc_write(val, addr) __raw_writeb(val, rtc_base + (addr)) |
93 | 94 | ||
94 | 95 | ||
95 | /* we rely on the rtc framework to handle locking (rtc->ops_lock), | 96 | /* we rely on the rtc framework to handle locking (rtc->ops_lock), |
@@ -330,32 +331,31 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
330 | return -ENOENT; | 331 | return -ENOENT; |
331 | } | 332 | } |
332 | 333 | ||
333 | /* NOTE: using static mapping for RTC registers */ | ||
334 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 334 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
335 | if (res && res->start != OMAP_RTC_BASE) { | 335 | if (!res) { |
336 | pr_debug("%s: RTC registers at %08x, expected %08x\n", | 336 | pr_debug("%s: RTC resource data missing\n", pdev->name); |
337 | pdev->name, (unsigned) res->start, OMAP_RTC_BASE); | ||
338 | return -ENOENT; | 337 | return -ENOENT; |
339 | } | 338 | } |
340 | 339 | ||
341 | if (res) | 340 | mem = request_mem_region(res->start, resource_size(res), pdev->name); |
342 | mem = request_mem_region(res->start, | ||
343 | res->end - res->start + 1, | ||
344 | pdev->name); | ||
345 | else | ||
346 | mem = NULL; | ||
347 | if (!mem) { | 341 | if (!mem) { |
348 | pr_debug("%s: RTC registers at %08x are not free\n", | 342 | pr_debug("%s: RTC registers at %08x are not free\n", |
349 | pdev->name, OMAP_RTC_BASE); | 343 | pdev->name, res->start); |
350 | return -EBUSY; | 344 | return -EBUSY; |
351 | } | 345 | } |
352 | 346 | ||
347 | rtc_base = ioremap(res->start, resource_size(res)); | ||
348 | if (!rtc_base) { | ||
349 | pr_debug("%s: RTC registers can't be mapped\n", pdev->name); | ||
350 | goto fail; | ||
351 | } | ||
352 | |||
353 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 353 | rtc = rtc_device_register(pdev->name, &pdev->dev, |
354 | &omap_rtc_ops, THIS_MODULE); | 354 | &omap_rtc_ops, THIS_MODULE); |
355 | if (IS_ERR(rtc)) { | 355 | if (IS_ERR(rtc)) { |
356 | pr_debug("%s: can't register RTC device, err %ld\n", | 356 | pr_debug("%s: can't register RTC device, err %ld\n", |
357 | pdev->name, PTR_ERR(rtc)); | 357 | pdev->name, PTR_ERR(rtc)); |
358 | goto fail; | 358 | goto fail0; |
359 | } | 359 | } |
360 | platform_set_drvdata(pdev, rtc); | 360 | platform_set_drvdata(pdev, rtc); |
361 | dev_set_drvdata(&rtc->dev, mem); | 361 | dev_set_drvdata(&rtc->dev, mem); |
@@ -380,13 +380,14 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
380 | dev_name(&rtc->dev), rtc)) { | 380 | dev_name(&rtc->dev), rtc)) { |
381 | pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", | 381 | pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", |
382 | pdev->name, omap_rtc_timer); | 382 | pdev->name, omap_rtc_timer); |
383 | goto fail0; | 383 | goto fail1; |
384 | } | 384 | } |
385 | if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, | 385 | if ((omap_rtc_timer != omap_rtc_alarm) && |
386 | dev_name(&rtc->dev), rtc)) { | 386 | (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, |
387 | dev_name(&rtc->dev), rtc))) { | ||
387 | pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", | 388 | pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", |
388 | pdev->name, omap_rtc_alarm); | 389 | pdev->name, omap_rtc_alarm); |
389 | goto fail1; | 390 | goto fail2; |
390 | } | 391 | } |
391 | 392 | ||
392 | /* On boards with split power, RTC_ON_NOFF won't reset the RTC */ | 393 | /* On boards with split power, RTC_ON_NOFF won't reset the RTC */ |
@@ -419,10 +420,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
419 | 420 | ||
420 | return 0; | 421 | return 0; |
421 | 422 | ||
422 | fail1: | 423 | fail2: |
423 | free_irq(omap_rtc_timer, NULL); | 424 | free_irq(omap_rtc_timer, NULL); |
424 | fail0: | 425 | fail1: |
425 | rtc_device_unregister(rtc); | 426 | rtc_device_unregister(rtc); |
427 | fail0: | ||
428 | iounmap(rtc_base); | ||
426 | fail: | 429 | fail: |
427 | release_resource(mem); | 430 | release_resource(mem); |
428 | return -EIO; | 431 | return -EIO; |
@@ -438,7 +441,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
438 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); | 441 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); |
439 | 442 | ||
440 | free_irq(omap_rtc_timer, rtc); | 443 | free_irq(omap_rtc_timer, rtc); |
441 | free_irq(omap_rtc_alarm, rtc); | 444 | |
445 | if (omap_rtc_timer != omap_rtc_alarm) | ||
446 | free_irq(omap_rtc_alarm, rtc); | ||
442 | 447 | ||
443 | release_resource(dev_get_drvdata(&rtc->dev)); | 448 | release_resource(dev_get_drvdata(&rtc->dev)); |
444 | rtc_device_unregister(rtc); | 449 | rtc_device_unregister(rtc); |
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 9b74e9c9151c..854c3cb365a1 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c | |||
@@ -58,6 +58,7 @@ struct pcf50633_time { | |||
58 | struct pcf50633_rtc { | 58 | struct pcf50633_rtc { |
59 | int alarm_enabled; | 59 | int alarm_enabled; |
60 | int second_enabled; | 60 | int second_enabled; |
61 | int alarm_pending; | ||
61 | 62 | ||
62 | struct pcf50633 *pcf; | 63 | struct pcf50633 *pcf; |
63 | struct rtc_device *rtc_dev; | 64 | struct rtc_device *rtc_dev; |
@@ -209,6 +210,7 @@ static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
209 | rtc = dev_get_drvdata(dev); | 210 | rtc = dev_get_drvdata(dev); |
210 | 211 | ||
211 | alrm->enabled = rtc->alarm_enabled; | 212 | alrm->enabled = rtc->alarm_enabled; |
213 | alrm->pending = rtc->alarm_pending; | ||
212 | 214 | ||
213 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, | 215 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, |
214 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | 216 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); |
@@ -244,6 +246,8 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
244 | /* Returns 0 on success */ | 246 | /* Returns 0 on success */ |
245 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, | 247 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, |
246 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | 248 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); |
249 | if (!alrm->enabled) | ||
250 | rtc->alarm_pending = 0; | ||
247 | 251 | ||
248 | if (!alarm_masked || alrm->enabled) | 252 | if (!alarm_masked || alrm->enabled) |
249 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | 253 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); |
@@ -268,6 +272,7 @@ static void pcf50633_rtc_irq(int irq, void *data) | |||
268 | switch (irq) { | 272 | switch (irq) { |
269 | case PCF50633_IRQ_ALARM: | 273 | case PCF50633_IRQ_ALARM: |
270 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | 274 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); |
275 | rtc->alarm_pending = 1; | ||
271 | break; | 276 | break; |
272 | case PCF50633_IRQ_SECOND: | 277 | case PCF50633_IRQ_SECOND: |
273 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); | 278 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); |
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b725913ccbe8..65f346b2fbae 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -212,6 +212,8 @@ static int pcf8563_probe(struct i2c_client *client, | |||
212 | 212 | ||
213 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 213 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
214 | 214 | ||
215 | i2c_set_clientdata(client, pcf8563); | ||
216 | |||
215 | pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, | 217 | pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, |
216 | &client->dev, &pcf8563_rtc_ops, THIS_MODULE); | 218 | &client->dev, &pcf8563_rtc_ops, THIS_MODULE); |
217 | 219 | ||
@@ -220,8 +222,6 @@ static int pcf8563_probe(struct i2c_client *client, | |||
220 | goto exit_kfree; | 222 | goto exit_kfree; |
221 | } | 223 | } |
222 | 224 | ||
223 | i2c_set_clientdata(client, pcf8563); | ||
224 | |||
225 | return 0; | 225 | return 0; |
226 | 226 | ||
227 | exit_kfree: | 227 | exit_kfree: |
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 7d33cda3f8f6..2d201afead3b 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c | |||
@@ -277,6 +277,8 @@ static int pcf8583_probe(struct i2c_client *client, | |||
277 | if (!pcf8583) | 277 | if (!pcf8583) |
278 | return -ENOMEM; | 278 | return -ENOMEM; |
279 | 279 | ||
280 | i2c_set_clientdata(client, pcf8583); | ||
281 | |||
280 | pcf8583->rtc = rtc_device_register(pcf8583_driver.driver.name, | 282 | pcf8583->rtc = rtc_device_register(pcf8583_driver.driver.name, |
281 | &client->dev, &pcf8583_rtc_ops, THIS_MODULE); | 283 | &client->dev, &pcf8583_rtc_ops, THIS_MODULE); |
282 | 284 | ||
@@ -285,7 +287,6 @@ static int pcf8583_probe(struct i2c_client *client, | |||
285 | goto exit_kfree; | 287 | goto exit_kfree; |
286 | } | 288 | } |
287 | 289 | ||
288 | i2c_set_clientdata(client, pcf8583); | ||
289 | return 0; | 290 | return 0; |
290 | 291 | ||
291 | exit_kfree: | 292 | exit_kfree: |
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index f41873f98f66..0264b117893b 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c | |||
@@ -51,10 +51,10 @@ static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |||
51 | 51 | ||
52 | switch (cmd) { | 52 | switch (cmd) { |
53 | case RTC_AIE_OFF: | 53 | case RTC_AIE_OFF: |
54 | __raw_writel(1, ldata->base + RTC_MIS); | 54 | writel(1, ldata->base + RTC_MIS); |
55 | return 0; | 55 | return 0; |
56 | case RTC_AIE_ON: | 56 | case RTC_AIE_ON: |
57 | __raw_writel(0, ldata->base + RTC_MIS); | 57 | writel(0, ldata->base + RTC_MIS); |
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
@@ -65,7 +65,7 @@ static int pl031_read_time(struct device *dev, struct rtc_time *tm) | |||
65 | { | 65 | { |
66 | struct pl031_local *ldata = dev_get_drvdata(dev); | 66 | struct pl031_local *ldata = dev_get_drvdata(dev); |
67 | 67 | ||
68 | rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm); | 68 | rtc_time_to_tm(readl(ldata->base + RTC_DR), tm); |
69 | 69 | ||
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
@@ -76,7 +76,7 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm) | |||
76 | struct pl031_local *ldata = dev_get_drvdata(dev); | 76 | struct pl031_local *ldata = dev_get_drvdata(dev); |
77 | 77 | ||
78 | rtc_tm_to_time(tm, &time); | 78 | rtc_tm_to_time(tm, &time); |
79 | __raw_writel(time, ldata->base + RTC_LR); | 79 | writel(time, ldata->base + RTC_LR); |
80 | 80 | ||
81 | return 0; | 81 | return 0; |
82 | } | 82 | } |
@@ -85,9 +85,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
85 | { | 85 | { |
86 | struct pl031_local *ldata = dev_get_drvdata(dev); | 86 | struct pl031_local *ldata = dev_get_drvdata(dev); |
87 | 87 | ||
88 | rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time); | 88 | rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time); |
89 | alarm->pending = __raw_readl(ldata->base + RTC_RIS); | 89 | alarm->pending = readl(ldata->base + RTC_RIS); |
90 | alarm->enabled = __raw_readl(ldata->base + RTC_IMSC); | 90 | alarm->enabled = readl(ldata->base + RTC_IMSC); |
91 | 91 | ||
92 | return 0; | 92 | return 0; |
93 | } | 93 | } |
@@ -99,8 +99,8 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
99 | 99 | ||
100 | rtc_tm_to_time(&alarm->time, &time); | 100 | rtc_tm_to_time(&alarm->time, &time); |
101 | 101 | ||
102 | __raw_writel(time, ldata->base + RTC_MR); | 102 | writel(time, ldata->base + RTC_MR); |
103 | __raw_writel(!alarm->enabled, ldata->base + RTC_MIS); | 103 | writel(!alarm->enabled, ldata->base + RTC_MIS); |
104 | 104 | ||
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
@@ -180,8 +180,9 @@ err_req: | |||
180 | 180 | ||
181 | static struct amba_id pl031_ids[] __initdata = { | 181 | static struct amba_id pl031_ids[] __initdata = { |
182 | { | 182 | { |
183 | .id = 0x00041031, | 183 | .id = 0x00041031, |
184 | .mask = 0x000fffff, }, | 184 | .mask = 0x000fffff, |
185 | }, | ||
185 | {0, 0}, | 186 | {0, 0}, |
186 | }; | 187 | }; |
187 | 188 | ||
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index d491eb265c38..67700831b5c9 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c | |||
@@ -62,7 +62,6 @@ | |||
62 | struct rtc_plat_data { | 62 | struct rtc_plat_data { |
63 | struct rtc_device *rtc; | 63 | struct rtc_device *rtc; |
64 | void __iomem *ioaddr; | 64 | void __iomem *ioaddr; |
65 | unsigned long baseaddr; | ||
66 | unsigned long last_jiffies; | 65 | unsigned long last_jiffies; |
67 | int irq; | 66 | int irq; |
68 | unsigned int irqen; | 67 | unsigned int irqen; |
@@ -70,6 +69,7 @@ struct rtc_plat_data { | |||
70 | int alrm_min; | 69 | int alrm_min; |
71 | int alrm_hour; | 70 | int alrm_hour; |
72 | int alrm_mday; | 71 | int alrm_mday; |
72 | spinlock_t lock; | ||
73 | }; | 73 | }; |
74 | 74 | ||
75 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) | 75 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
142 | unsigned long irqflags; | 142 | unsigned long irqflags; |
143 | u8 flags; | 143 | u8 flags; |
144 | 144 | ||
145 | spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); | 145 | spin_lock_irqsave(&pdata->lock, irqflags); |
146 | 146 | ||
147 | flags = readb(ioaddr + RTC_FLAGS); | 147 | flags = readb(ioaddr + RTC_FLAGS); |
148 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | 148 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); |
@@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
162 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); | 162 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); |
163 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | 163 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ |
164 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | 164 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); |
165 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); | 165 | spin_unlock_irqrestore(&pdata->lock, irqflags); |
166 | } | 166 | } |
167 | 167 | ||
168 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 168 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
@@ -202,56 +202,53 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) | |||
202 | struct platform_device *pdev = dev_id; | 202 | struct platform_device *pdev = dev_id; |
203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
204 | void __iomem *ioaddr = pdata->ioaddr; | 204 | void __iomem *ioaddr = pdata->ioaddr; |
205 | unsigned long events = RTC_IRQF; | 205 | unsigned long events = 0; |
206 | 206 | ||
207 | spin_lock(&pdata->lock); | ||
207 | /* read and clear interrupt */ | 208 | /* read and clear interrupt */ |
208 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | 209 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { |
209 | return IRQ_NONE; | 210 | events = RTC_IRQF; |
210 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | 211 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) |
211 | events |= RTC_UF; | 212 | events |= RTC_UF; |
212 | else | 213 | else |
213 | events |= RTC_AF; | 214 | events |= RTC_AF; |
214 | rtc_update_irq(pdata->rtc, 1, events); | 215 | if (likely(pdata->rtc)) |
215 | return IRQ_HANDLED; | 216 | rtc_update_irq(pdata->rtc, 1, events); |
217 | } | ||
218 | spin_unlock(&pdata->lock); | ||
219 | return events ? IRQ_HANDLED : IRQ_NONE; | ||
216 | } | 220 | } |
217 | 221 | ||
218 | static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, | 222 | static int stk17ta8_rtc_alarm_irq_enable(struct device *dev, |
219 | unsigned long arg) | 223 | unsigned int enabled) |
220 | { | 224 | { |
221 | struct platform_device *pdev = to_platform_device(dev); | 225 | struct platform_device *pdev = to_platform_device(dev); |
222 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 226 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
223 | 227 | ||
224 | if (pdata->irq <= 0) | 228 | if (pdata->irq <= 0) |
225 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | 229 | return -EINVAL; |
226 | switch (cmd) { | 230 | if (enabled) |
227 | case RTC_AIE_OFF: | ||
228 | pdata->irqen &= ~RTC_AF; | ||
229 | stk17ta8_rtc_update_alarm(pdata); | ||
230 | break; | ||
231 | case RTC_AIE_ON: | ||
232 | pdata->irqen |= RTC_AF; | 231 | pdata->irqen |= RTC_AF; |
233 | stk17ta8_rtc_update_alarm(pdata); | 232 | else |
234 | break; | 233 | pdata->irqen &= ~RTC_AF; |
235 | default: | 234 | stk17ta8_rtc_update_alarm(pdata); |
236 | return -ENOIOCTLCMD; | ||
237 | } | ||
238 | return 0; | 235 | return 0; |
239 | } | 236 | } |
240 | 237 | ||
241 | static const struct rtc_class_ops stk17ta8_rtc_ops = { | 238 | static const struct rtc_class_ops stk17ta8_rtc_ops = { |
242 | .read_time = stk17ta8_rtc_read_time, | 239 | .read_time = stk17ta8_rtc_read_time, |
243 | .set_time = stk17ta8_rtc_set_time, | 240 | .set_time = stk17ta8_rtc_set_time, |
244 | .read_alarm = stk17ta8_rtc_read_alarm, | 241 | .read_alarm = stk17ta8_rtc_read_alarm, |
245 | .set_alarm = stk17ta8_rtc_set_alarm, | 242 | .set_alarm = stk17ta8_rtc_set_alarm, |
246 | .ioctl = stk17ta8_rtc_ioctl, | 243 | .alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable, |
247 | }; | 244 | }; |
248 | 245 | ||
249 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, | 246 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, |
250 | struct bin_attribute *attr, char *buf, | 247 | struct bin_attribute *attr, char *buf, |
251 | loff_t pos, size_t size) | 248 | loff_t pos, size_t size) |
252 | { | 249 | { |
253 | struct platform_device *pdev = | 250 | struct device *dev = container_of(kobj, struct device, kobj); |
254 | to_platform_device(container_of(kobj, struct device, kobj)); | 251 | struct platform_device *pdev = to_platform_device(dev); |
255 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 252 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
256 | void __iomem *ioaddr = pdata->ioaddr; | 253 | void __iomem *ioaddr = pdata->ioaddr; |
257 | ssize_t count; | 254 | ssize_t count; |
@@ -265,8 +262,8 @@ static ssize_t stk17ta8_nvram_write(struct kobject *kobj, | |||
265 | struct bin_attribute *attr, char *buf, | 262 | struct bin_attribute *attr, char *buf, |
266 | loff_t pos, size_t size) | 263 | loff_t pos, size_t size) |
267 | { | 264 | { |
268 | struct platform_device *pdev = | 265 | struct device *dev = container_of(kobj, struct device, kobj); |
269 | to_platform_device(container_of(kobj, struct device, kobj)); | 266 | struct platform_device *pdev = to_platform_device(dev); |
270 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 267 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
271 | void __iomem *ioaddr = pdata->ioaddr; | 268 | void __iomem *ioaddr = pdata->ioaddr; |
272 | ssize_t count; | 269 | ssize_t count; |
@@ -288,31 +285,26 @@ static struct bin_attribute stk17ta8_nvram_attr = { | |||
288 | 285 | ||
289 | static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) | 286 | static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) |
290 | { | 287 | { |
291 | struct rtc_device *rtc; | ||
292 | struct resource *res; | 288 | struct resource *res; |
293 | unsigned int cal; | 289 | unsigned int cal; |
294 | unsigned int flags; | 290 | unsigned int flags; |
295 | struct rtc_plat_data *pdata; | 291 | struct rtc_plat_data *pdata; |
296 | void __iomem *ioaddr = NULL; | 292 | void __iomem *ioaddr; |
297 | int ret = 0; | 293 | int ret = 0; |
298 | 294 | ||
299 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 295 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
300 | if (!res) | 296 | if (!res) |
301 | return -ENODEV; | 297 | return -ENODEV; |
302 | 298 | ||
303 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 299 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
304 | if (!pdata) | 300 | if (!pdata) |
305 | return -ENOMEM; | 301 | return -ENOMEM; |
306 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | 302 | if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, |
307 | ret = -EBUSY; | 303 | pdev->name)) |
308 | goto out; | 304 | return -EBUSY; |
309 | } | 305 | ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); |
310 | pdata->baseaddr = res->start; | 306 | if (!ioaddr) |
311 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | 307 | return -ENOMEM; |
312 | if (!ioaddr) { | ||
313 | ret = -ENOMEM; | ||
314 | goto out; | ||
315 | } | ||
316 | pdata->ioaddr = ioaddr; | 308 | pdata->ioaddr = ioaddr; |
317 | pdata->irq = platform_get_irq(pdev, 0); | 309 | pdata->irq = platform_get_irq(pdev, 0); |
318 | 310 | ||
@@ -328,9 +320,13 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) | |||
328 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) | 320 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) |
329 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 321 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
330 | 322 | ||
323 | spin_lock_init(&pdata->lock); | ||
324 | pdata->last_jiffies = jiffies; | ||
325 | platform_set_drvdata(pdev, pdata); | ||
331 | if (pdata->irq > 0) { | 326 | if (pdata->irq > 0) { |
332 | writeb(0, ioaddr + RTC_INTERRUPTS); | 327 | writeb(0, ioaddr + RTC_INTERRUPTS); |
333 | if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, | 328 | if (devm_request_irq(&pdev->dev, pdata->irq, |
329 | stk17ta8_rtc_interrupt, | ||
334 | IRQF_DISABLED | IRQF_SHARED, | 330 | IRQF_DISABLED | IRQF_SHARED, |
335 | pdev->name, pdev) < 0) { | 331 | pdev->name, pdev) < 0) { |
336 | dev_warn(&pdev->dev, "interrupt not available.\n"); | 332 | dev_warn(&pdev->dev, "interrupt not available.\n"); |
@@ -338,29 +334,14 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) | |||
338 | } | 334 | } |
339 | } | 335 | } |
340 | 336 | ||
341 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 337 | pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, |
342 | &stk17ta8_rtc_ops, THIS_MODULE); | 338 | &stk17ta8_rtc_ops, THIS_MODULE); |
343 | if (IS_ERR(rtc)) { | 339 | if (IS_ERR(pdata->rtc)) |
344 | ret = PTR_ERR(rtc); | 340 | return PTR_ERR(pdata->rtc); |
345 | goto out; | 341 | |
346 | } | ||
347 | pdata->rtc = rtc; | ||
348 | pdata->last_jiffies = jiffies; | ||
349 | platform_set_drvdata(pdev, pdata); | ||
350 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | 342 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); |
351 | if (ret) | 343 | if (ret) |
352 | goto out; | ||
353 | return 0; | ||
354 | out: | ||
355 | if (pdata->rtc) | ||
356 | rtc_device_unregister(pdata->rtc); | 344 | rtc_device_unregister(pdata->rtc); |
357 | if (pdata->irq > 0) | ||
358 | free_irq(pdata->irq, pdev); | ||
359 | if (ioaddr) | ||
360 | iounmap(ioaddr); | ||
361 | if (pdata->baseaddr) | ||
362 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
363 | kfree(pdata); | ||
364 | return ret; | 345 | return ret; |
365 | } | 346 | } |
366 | 347 | ||
@@ -370,13 +351,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) | |||
370 | 351 | ||
371 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | 352 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); |
372 | rtc_device_unregister(pdata->rtc); | 353 | rtc_device_unregister(pdata->rtc); |
373 | if (pdata->irq > 0) { | 354 | if (pdata->irq > 0) |
374 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | 355 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); |
375 | free_irq(pdata->irq, pdev); | ||
376 | } | ||
377 | iounmap(pdata->ioaddr); | ||
378 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
379 | kfree(pdata); | ||
380 | return 0; | 356 | return 0; |
381 | } | 357 | } |
382 | 358 | ||
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4a6ed1104fbb..9ee81d8aa7c0 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c | |||
@@ -17,6 +17,7 @@ | |||
17 | struct tx4939rtc_plat_data { | 17 | struct tx4939rtc_plat_data { |
18 | struct rtc_device *rtc; | 18 | struct rtc_device *rtc; |
19 | struct tx4939_rtc_reg __iomem *rtcreg; | 19 | struct tx4939_rtc_reg __iomem *rtcreg; |
20 | spinlock_t lock; | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) | 23 | static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) |
@@ -52,14 +53,14 @@ static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs) | |||
52 | buf[3] = secs >> 8; | 53 | buf[3] = secs >> 8; |
53 | buf[4] = secs >> 16; | 54 | buf[4] = secs >> 16; |
54 | buf[5] = secs >> 24; | 55 | buf[5] = secs >> 24; |
55 | spin_lock_irq(&pdata->rtc->irq_lock); | 56 | spin_lock_irq(&pdata->lock); |
56 | __raw_writel(0, &rtcreg->adr); | 57 | __raw_writel(0, &rtcreg->adr); |
57 | for (i = 0; i < 6; i++) | 58 | for (i = 0; i < 6; i++) |
58 | __raw_writel(buf[i], &rtcreg->dat); | 59 | __raw_writel(buf[i], &rtcreg->dat); |
59 | ret = tx4939_rtc_cmd(rtcreg, | 60 | ret = tx4939_rtc_cmd(rtcreg, |
60 | TX4939_RTCCTL_COMMAND_SETTIME | | 61 | TX4939_RTCCTL_COMMAND_SETTIME | |
61 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); | 62 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); |
62 | spin_unlock_irq(&pdata->rtc->irq_lock); | 63 | spin_unlock_irq(&pdata->lock); |
63 | return ret; | 64 | return ret; |
64 | } | 65 | } |
65 | 66 | ||
@@ -71,18 +72,18 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
71 | unsigned long sec; | 72 | unsigned long sec; |
72 | unsigned char buf[6]; | 73 | unsigned char buf[6]; |
73 | 74 | ||
74 | spin_lock_irq(&pdata->rtc->irq_lock); | 75 | spin_lock_irq(&pdata->lock); |
75 | ret = tx4939_rtc_cmd(rtcreg, | 76 | ret = tx4939_rtc_cmd(rtcreg, |
76 | TX4939_RTCCTL_COMMAND_GETTIME | | 77 | TX4939_RTCCTL_COMMAND_GETTIME | |
77 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); | 78 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); |
78 | if (ret) { | 79 | if (ret) { |
79 | spin_unlock_irq(&pdata->rtc->irq_lock); | 80 | spin_unlock_irq(&pdata->lock); |
80 | return ret; | 81 | return ret; |
81 | } | 82 | } |
82 | __raw_writel(2, &rtcreg->adr); | 83 | __raw_writel(2, &rtcreg->adr); |
83 | for (i = 2; i < 6; i++) | 84 | for (i = 2; i < 6; i++) |
84 | buf[i] = __raw_readl(&rtcreg->dat); | 85 | buf[i] = __raw_readl(&rtcreg->dat); |
85 | spin_unlock_irq(&pdata->rtc->irq_lock); | 86 | spin_unlock_irq(&pdata->lock); |
86 | sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; | 87 | sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; |
87 | rtc_time_to_tm(sec, tm); | 88 | rtc_time_to_tm(sec, tm); |
88 | return rtc_valid_tm(tm); | 89 | return rtc_valid_tm(tm); |
@@ -110,13 +111,13 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
110 | buf[3] = sec >> 8; | 111 | buf[3] = sec >> 8; |
111 | buf[4] = sec >> 16; | 112 | buf[4] = sec >> 16; |
112 | buf[5] = sec >> 24; | 113 | buf[5] = sec >> 24; |
113 | spin_lock_irq(&pdata->rtc->irq_lock); | 114 | spin_lock_irq(&pdata->lock); |
114 | __raw_writel(0, &rtcreg->adr); | 115 | __raw_writel(0, &rtcreg->adr); |
115 | for (i = 0; i < 6; i++) | 116 | for (i = 0; i < 6; i++) |
116 | __raw_writel(buf[i], &rtcreg->dat); | 117 | __raw_writel(buf[i], &rtcreg->dat); |
117 | ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | | 118 | ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | |
118 | (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); | 119 | (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); |
119 | spin_unlock_irq(&pdata->rtc->irq_lock); | 120 | spin_unlock_irq(&pdata->lock); |
120 | return ret; | 121 | return ret; |
121 | } | 122 | } |
122 | 123 | ||
@@ -129,12 +130,12 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
129 | unsigned char buf[6]; | 130 | unsigned char buf[6]; |
130 | u32 ctl; | 131 | u32 ctl; |
131 | 132 | ||
132 | spin_lock_irq(&pdata->rtc->irq_lock); | 133 | spin_lock_irq(&pdata->lock); |
133 | ret = tx4939_rtc_cmd(rtcreg, | 134 | ret = tx4939_rtc_cmd(rtcreg, |
134 | TX4939_RTCCTL_COMMAND_GETALARM | | 135 | TX4939_RTCCTL_COMMAND_GETALARM | |
135 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); | 136 | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); |
136 | if (ret) { | 137 | if (ret) { |
137 | spin_unlock_irq(&pdata->rtc->irq_lock); | 138 | spin_unlock_irq(&pdata->lock); |
138 | return ret; | 139 | return ret; |
139 | } | 140 | } |
140 | __raw_writel(2, &rtcreg->adr); | 141 | __raw_writel(2, &rtcreg->adr); |
@@ -143,7 +144,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
143 | ctl = __raw_readl(&rtcreg->ctl); | 144 | ctl = __raw_readl(&rtcreg->ctl); |
144 | alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; | 145 | alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; |
145 | alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; | 146 | alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; |
146 | spin_unlock_irq(&pdata->rtc->irq_lock); | 147 | spin_unlock_irq(&pdata->lock); |
147 | sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; | 148 | sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; |
148 | rtc_time_to_tm(sec, &alrm->time); | 149 | rtc_time_to_tm(sec, &alrm->time); |
149 | return rtc_valid_tm(&alrm->time); | 150 | return rtc_valid_tm(&alrm->time); |
@@ -153,11 +154,11 @@ static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | |||
153 | { | 154 | { |
154 | struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); | 155 | struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); |
155 | 156 | ||
156 | spin_lock_irq(&pdata->rtc->irq_lock); | 157 | spin_lock_irq(&pdata->lock); |
157 | tx4939_rtc_cmd(pdata->rtcreg, | 158 | tx4939_rtc_cmd(pdata->rtcreg, |
158 | TX4939_RTCCTL_COMMAND_NOP | | 159 | TX4939_RTCCTL_COMMAND_NOP | |
159 | (enabled ? TX4939_RTCCTL_ALME : 0)); | 160 | (enabled ? TX4939_RTCCTL_ALME : 0)); |
160 | spin_unlock_irq(&pdata->rtc->irq_lock); | 161 | spin_unlock_irq(&pdata->lock); |
161 | return 0; | 162 | return 0; |
162 | } | 163 | } |
163 | 164 | ||
@@ -167,13 +168,14 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) | |||
167 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; | 168 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; |
168 | unsigned long events = RTC_IRQF; | 169 | unsigned long events = RTC_IRQF; |
169 | 170 | ||
170 | spin_lock(&pdata->rtc->irq_lock); | 171 | spin_lock(&pdata->lock); |
171 | if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { | 172 | if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { |
172 | events |= RTC_AF; | 173 | events |= RTC_AF; |
173 | tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); | 174 | tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); |
174 | } | 175 | } |
175 | spin_unlock(&pdata->rtc->irq_lock); | 176 | spin_unlock(&pdata->lock); |
176 | rtc_update_irq(pdata->rtc, 1, events); | 177 | if (likely(pdata->rtc)) |
178 | rtc_update_irq(pdata->rtc, 1, events); | ||
177 | return IRQ_HANDLED; | 179 | return IRQ_HANDLED; |
178 | } | 180 | } |
179 | 181 | ||
@@ -194,13 +196,13 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj, | |||
194 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; | 196 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; |
195 | ssize_t count; | 197 | ssize_t count; |
196 | 198 | ||
197 | spin_lock_irq(&pdata->rtc->irq_lock); | 199 | spin_lock_irq(&pdata->lock); |
198 | for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; | 200 | for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; |
199 | count++, size--) { | 201 | count++, size--) { |
200 | __raw_writel(pos++, &rtcreg->adr); | 202 | __raw_writel(pos++, &rtcreg->adr); |
201 | *buf++ = __raw_readl(&rtcreg->dat); | 203 | *buf++ = __raw_readl(&rtcreg->dat); |
202 | } | 204 | } |
203 | spin_unlock_irq(&pdata->rtc->irq_lock); | 205 | spin_unlock_irq(&pdata->lock); |
204 | return count; | 206 | return count; |
205 | } | 207 | } |
206 | 208 | ||
@@ -213,13 +215,13 @@ static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj, | |||
213 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; | 215 | struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; |
214 | ssize_t count; | 216 | ssize_t count; |
215 | 217 | ||
216 | spin_lock_irq(&pdata->rtc->irq_lock); | 218 | spin_lock_irq(&pdata->lock); |
217 | for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; | 219 | for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; |
218 | count++, size--) { | 220 | count++, size--) { |
219 | __raw_writel(pos++, &rtcreg->adr); | 221 | __raw_writel(pos++, &rtcreg->adr); |
220 | __raw_writel(*buf++, &rtcreg->dat); | 222 | __raw_writel(*buf++, &rtcreg->dat); |
221 | } | 223 | } |
222 | spin_unlock_irq(&pdata->rtc->irq_lock); | 224 | spin_unlock_irq(&pdata->lock); |
223 | return count; | 225 | return count; |
224 | } | 226 | } |
225 | 227 | ||
@@ -259,6 +261,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) | |||
259 | if (!pdata->rtcreg) | 261 | if (!pdata->rtcreg) |
260 | return -EBUSY; | 262 | return -EBUSY; |
261 | 263 | ||
264 | spin_lock_init(&pdata->lock); | ||
262 | tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); | 265 | tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); |
263 | if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, | 266 | if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, |
264 | IRQF_DISABLED, pdev->name, &pdev->dev) < 0) | 267 | IRQF_DISABLED, pdev->name, &pdev->dev) < 0) |
@@ -277,14 +280,12 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) | |||
277 | static int __exit tx4939_rtc_remove(struct platform_device *pdev) | 280 | static int __exit tx4939_rtc_remove(struct platform_device *pdev) |
278 | { | 281 | { |
279 | struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); | 282 | struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); |
280 | struct rtc_device *rtc = pdata->rtc; | ||
281 | 283 | ||
282 | spin_lock_irq(&rtc->irq_lock); | ||
283 | tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); | ||
284 | spin_unlock_irq(&rtc->irq_lock); | ||
285 | sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); | 284 | sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); |
286 | rtc_device_unregister(rtc); | 285 | rtc_device_unregister(pdata->rtc); |
287 | platform_set_drvdata(pdev, NULL); | 286 | spin_lock_irq(&pdata->lock); |
287 | tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); | ||
288 | spin_unlock_irq(&pdata->lock); | ||
288 | return 0; | 289 | return 0; |
289 | } | 290 | } |
290 | 291 | ||
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index ad741afd47d8..bed4cab07043 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c | |||
@@ -304,7 +304,6 @@ static int rtc_probe(struct platform_device *pdev) | |||
304 | { | 304 | { |
305 | struct v3020_platform_data *pdata = pdev->dev.platform_data; | 305 | struct v3020_platform_data *pdata = pdev->dev.platform_data; |
306 | struct v3020 *chip; | 306 | struct v3020 *chip; |
307 | struct rtc_device *rtc; | ||
308 | int retval = -EBUSY; | 307 | int retval = -EBUSY; |
309 | int i; | 308 | int i; |
310 | int temp; | 309 | int temp; |
@@ -353,13 +352,12 @@ static int rtc_probe(struct platform_device *pdev) | |||
353 | 352 | ||
354 | platform_set_drvdata(pdev, chip); | 353 | platform_set_drvdata(pdev, chip); |
355 | 354 | ||
356 | rtc = rtc_device_register("v3020", | 355 | chip->rtc = rtc_device_register("v3020", |
357 | &pdev->dev, &v3020_rtc_ops, THIS_MODULE); | 356 | &pdev->dev, &v3020_rtc_ops, THIS_MODULE); |
358 | if (IS_ERR(rtc)) { | 357 | if (IS_ERR(chip->rtc)) { |
359 | retval = PTR_ERR(rtc); | 358 | retval = PTR_ERR(chip->rtc); |
360 | goto err_io; | 359 | goto err_io; |
361 | } | 360 | } |
362 | chip->rtc = rtc; | ||
363 | 361 | ||
364 | return 0; | 362 | return 0; |
365 | 363 | ||
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index fadddac1e5a4..c3244244e8cf 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c | |||
@@ -327,7 +327,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) | |||
327 | if (!res) | 327 | if (!res) |
328 | return -EBUSY; | 328 | return -EBUSY; |
329 | 329 | ||
330 | rtc1_base = ioremap(res->start, res->end - res->start + 1); | 330 | rtc1_base = ioremap(res->start, resource_size(res)); |
331 | if (!rtc1_base) | 331 | if (!rtc1_base) |
332 | return -EBUSY; | 332 | return -EBUSY; |
333 | 333 | ||
@@ -337,7 +337,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) | |||
337 | goto err_rtc1_iounmap; | 337 | goto err_rtc1_iounmap; |
338 | } | 338 | } |
339 | 339 | ||
340 | rtc2_base = ioremap(res->start, res->end - res->start + 1); | 340 | rtc2_base = ioremap(res->start, resource_size(res)); |
341 | if (!rtc2_base) { | 341 | if (!rtc2_base) { |
342 | retval = -EBUSY; | 342 | retval = -EBUSY; |
343 | goto err_rtc1_iounmap; | 343 | goto err_rtc1_iounmap; |
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index f16486635a8e..f1e440521c54 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c | |||
@@ -354,8 +354,9 @@ static const struct rtc_class_ops wm8350_rtc_ops = { | |||
354 | }; | 354 | }; |
355 | 355 | ||
356 | #ifdef CONFIG_PM | 356 | #ifdef CONFIG_PM |
357 | static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 357 | static int wm8350_rtc_suspend(struct device *dev) |
358 | { | 358 | { |
359 | struct platform_device *pdev = to_platform_device(dev); | ||
359 | struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); | 360 | struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); |
360 | int ret = 0; | 361 | int ret = 0; |
361 | u16 reg; | 362 | u16 reg; |
@@ -373,8 +374,9 @@ static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
373 | return ret; | 374 | return ret; |
374 | } | 375 | } |
375 | 376 | ||
376 | static int wm8350_rtc_resume(struct platform_device *pdev) | 377 | static int wm8350_rtc_resume(struct device *dev) |
377 | { | 378 | { |
379 | struct platform_device *pdev = to_platform_device(dev); | ||
378 | struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); | 380 | struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); |
379 | int ret; | 381 | int ret; |
380 | 382 | ||
@@ -484,13 +486,17 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev) | |||
484 | return 0; | 486 | return 0; |
485 | } | 487 | } |
486 | 488 | ||
489 | static struct dev_pm_ops wm8350_rtc_pm_ops = { | ||
490 | .suspend = wm8350_rtc_suspend, | ||
491 | .resume = wm8350_rtc_resume, | ||
492 | }; | ||
493 | |||
487 | static struct platform_driver wm8350_rtc_driver = { | 494 | static struct platform_driver wm8350_rtc_driver = { |
488 | .probe = wm8350_rtc_probe, | 495 | .probe = wm8350_rtc_probe, |
489 | .remove = __devexit_p(wm8350_rtc_remove), | 496 | .remove = __devexit_p(wm8350_rtc_remove), |
490 | .suspend = wm8350_rtc_suspend, | ||
491 | .resume = wm8350_rtc_resume, | ||
492 | .driver = { | 497 | .driver = { |
493 | .name = "wm8350-rtc", | 498 | .name = "wm8350-rtc", |
499 | .pm = &wm8350_rtc_pm_ops, | ||
494 | }, | 500 | }, |
495 | }; | 501 | }; |
496 | 502 | ||
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 6583c1a8b070..9aae49139a0a 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c | |||
@@ -155,11 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) | |||
155 | } | 155 | } |
156 | 156 | ||
157 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | 157 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, |
158 | int datetoo, u8 reg_base, unsigned char alm_enable) | 158 | u8 reg_base, unsigned char alm_enable) |
159 | { | 159 | { |
160 | int i, xfer, nbytes; | 160 | int i, xfer; |
161 | unsigned char buf[8]; | ||
162 | unsigned char rdata[10] = { 0, reg_base }; | 161 | unsigned char rdata[10] = { 0, reg_base }; |
162 | unsigned char *buf = rdata + 2; | ||
163 | 163 | ||
164 | static const unsigned char wel[3] = { 0, X1205_REG_SR, | 164 | static const unsigned char wel[3] = { 0, X1205_REG_SR, |
165 | X1205_SR_WEL }; | 165 | X1205_SR_WEL }; |
@@ -170,9 +170,9 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
170 | static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; | 170 | static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; |
171 | 171 | ||
172 | dev_dbg(&client->dev, | 172 | dev_dbg(&client->dev, |
173 | "%s: secs=%d, mins=%d, hours=%d\n", | 173 | "%s: sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d\n", |
174 | __func__, | 174 | __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, |
175 | tm->tm_sec, tm->tm_min, tm->tm_hour); | 175 | tm->tm_mon, tm->tm_year, tm->tm_wday); |
176 | 176 | ||
177 | buf[CCR_SEC] = bin2bcd(tm->tm_sec); | 177 | buf[CCR_SEC] = bin2bcd(tm->tm_sec); |
178 | buf[CCR_MIN] = bin2bcd(tm->tm_min); | 178 | buf[CCR_MIN] = bin2bcd(tm->tm_min); |
@@ -180,23 +180,15 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
180 | /* set hour and 24hr bit */ | 180 | /* set hour and 24hr bit */ |
181 | buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL; | 181 | buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL; |
182 | 182 | ||
183 | /* should we also set the date? */ | 183 | buf[CCR_MDAY] = bin2bcd(tm->tm_mday); |
184 | if (datetoo) { | ||
185 | dev_dbg(&client->dev, | ||
186 | "%s: mday=%d, mon=%d, year=%d, wday=%d\n", | ||
187 | __func__, | ||
188 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
189 | 184 | ||
190 | buf[CCR_MDAY] = bin2bcd(tm->tm_mday); | 185 | /* month, 1 - 12 */ |
186 | buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); | ||
191 | 187 | ||
192 | /* month, 1 - 12 */ | 188 | /* year, since the rtc epoch*/ |
193 | buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); | 189 | buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); |
194 | 190 | buf[CCR_WDAY] = tm->tm_wday & 0x07; | |
195 | /* year, since the rtc epoch*/ | 191 | buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100); |
196 | buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); | ||
197 | buf[CCR_WDAY] = tm->tm_wday & 0x07; | ||
198 | buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100); | ||
199 | } | ||
200 | 192 | ||
201 | /* If writing alarm registers, set compare bits on registers 0-4 */ | 193 | /* If writing alarm registers, set compare bits on registers 0-4 */ |
202 | if (reg_base < X1205_CCR_BASE) | 194 | if (reg_base < X1205_CCR_BASE) |
@@ -214,17 +206,8 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
214 | return -EIO; | 206 | return -EIO; |
215 | } | 207 | } |
216 | 208 | ||
217 | 209 | xfer = i2c_master_send(client, rdata, sizeof(rdata)); | |
218 | /* write register's data */ | 210 | if (xfer != sizeof(rdata)) { |
219 | if (datetoo) | ||
220 | nbytes = 8; | ||
221 | else | ||
222 | nbytes = 3; | ||
223 | for (i = 0; i < nbytes; i++) | ||
224 | rdata[2+i] = buf[i]; | ||
225 | |||
226 | xfer = i2c_master_send(client, rdata, nbytes+2); | ||
227 | if (xfer != nbytes+2) { | ||
228 | dev_err(&client->dev, | 211 | dev_err(&client->dev, |
229 | "%s: result=%d addr=%02x, data=%02x\n", | 212 | "%s: result=%d addr=%02x, data=%02x\n", |
230 | __func__, | 213 | __func__, |
@@ -282,7 +265,7 @@ static int x1205_fix_osc(struct i2c_client *client) | |||
282 | 265 | ||
283 | memset(&tm, 0, sizeof(tm)); | 266 | memset(&tm, 0, sizeof(tm)); |
284 | 267 | ||
285 | err = x1205_set_datetime(client, &tm, 1, X1205_CCR_BASE, 0); | 268 | err = x1205_set_datetime(client, &tm, X1205_CCR_BASE, 0); |
286 | if (err < 0) | 269 | if (err < 0) |
287 | dev_err(&client->dev, "unable to restart the oscillator\n"); | 270 | dev_err(&client->dev, "unable to restart the oscillator\n"); |
288 | 271 | ||
@@ -481,7 +464,7 @@ static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
481 | static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 464 | static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
482 | { | 465 | { |
483 | return x1205_set_datetime(to_i2c_client(dev), | 466 | return x1205_set_datetime(to_i2c_client(dev), |
484 | &alrm->time, 1, X1205_ALM0_BASE, alrm->enabled); | 467 | &alrm->time, X1205_ALM0_BASE, alrm->enabled); |
485 | } | 468 | } |
486 | 469 | ||
487 | static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) | 470 | static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) |
@@ -493,7 +476,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
493 | static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) | 476 | static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) |
494 | { | 477 | { |
495 | return x1205_set_datetime(to_i2c_client(dev), | 478 | return x1205_set_datetime(to_i2c_client(dev), |
496 | tm, 1, X1205_CCR_BASE, 0); | 479 | tm, X1205_CCR_BASE, 0); |
497 | } | 480 | } |
498 | 481 | ||
499 | static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) | 482 | static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) |
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c index f78b8912d905..89c8fe2997fa 100644 --- a/drivers/staging/cx25821/cx25821-audups11.c +++ b/drivers/staging/cx25821/cx25821-audups11.c | |||
@@ -94,36 +94,20 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | 101 | ||
103 | lock_kernel(); | 102 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
104 | list_for_each(list, &cx25821_devlist) { | 103 | v4l2_type_names[type]); |
105 | h = list_entry(list, struct cx25821_dev, devlist); | ||
106 | |||
107 | if (h->video_dev[SRAM_CH11] | ||
108 | && h->video_dev[SRAM_CH11]->minor == minor) { | ||
109 | dev = h; | ||
110 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (NULL == dev) { | ||
115 | unlock_kernel(); | ||
116 | return -ENODEV; | ||
117 | } | ||
118 | |||
119 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
120 | 104 | ||
121 | /* allocate + initialize per filehandle data */ | 105 | /* allocate + initialize per filehandle data */ |
122 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 106 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
123 | if (NULL == fh) { | 107 | if (NULL == fh) |
124 | unlock_kernel(); | ||
125 | return -ENOMEM; | 108 | return -ENOMEM; |
126 | } | 109 | |
110 | lock_kernel(); | ||
127 | 111 | ||
128 | file->private_data = fh; | 112 | file->private_data = fh; |
129 | fh->dev = dev; | 113 | fh->dev = dev; |
@@ -427,7 +411,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
427 | struct video_device cx25821_video_template11 = { | 411 | struct video_device cx25821_video_template11 = { |
428 | .name = "cx25821-audioupstream", | 412 | .name = "cx25821-audioupstream", |
429 | .fops = &video_fops, | 413 | .fops = &video_fops, |
430 | .minor = -1, | ||
431 | .ioctl_ops = &video_ioctl_ops, | 414 | .ioctl_ops = &video_ioctl_ops, |
432 | .tvnorms = CX25821_NORMS, | 415 | .tvnorms = CX25821_NORMS, |
433 | .current_norm = V4L2_STD_NTSC_M, | 416 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c index 8834bc80a5ab..c7c14c7698a7 100644 --- a/drivers/staging/cx25821/cx25821-video.c +++ b/drivers/staging/cx25821/cx25821-video.c | |||
@@ -184,11 +184,11 @@ struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, | |||
184 | if (NULL == vfd) | 184 | if (NULL == vfd) |
185 | return NULL; | 185 | return NULL; |
186 | *vfd = *template; | 186 | *vfd = *template; |
187 | vfd->minor = -1; | ||
188 | vfd->v4l2_dev = &dev->v4l2_dev; | 187 | vfd->v4l2_dev = &dev->v4l2_dev; |
189 | vfd->release = video_device_release; | 188 | vfd->release = video_device_release; |
190 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, | 189 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, |
191 | cx25821_boards[dev->board].name); | 190 | cx25821_boards[dev->board].name); |
191 | video_set_drvdata(vfd, dev); | ||
192 | return vfd; | 192 | return vfd; |
193 | } | 193 | } |
194 | 194 | ||
@@ -424,7 +424,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) | |||
424 | void cx25821_videoioctl_unregister(struct cx25821_dev *dev) | 424 | void cx25821_videoioctl_unregister(struct cx25821_dev *dev) |
425 | { | 425 | { |
426 | if (dev->ioctl_dev) { | 426 | if (dev->ioctl_dev) { |
427 | if (dev->ioctl_dev->minor != -1) | 427 | if (video_is_registered(dev->ioctl_dev)) |
428 | video_unregister_device(dev->ioctl_dev); | 428 | video_unregister_device(dev->ioctl_dev); |
429 | else | 429 | else |
430 | video_device_release(dev->ioctl_dev); | 430 | video_device_release(dev->ioctl_dev); |
@@ -438,7 +438,7 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) | |||
438 | cx_clear(PCI_INT_MSK, 1); | 438 | cx_clear(PCI_INT_MSK, 1); |
439 | 439 | ||
440 | if (dev->video_dev[chan_num]) { | 440 | if (dev->video_dev[chan_num]) { |
441 | if (-1 != dev->video_dev[chan_num]->minor) | 441 | if (video_is_registered(dev->video_dev[chan_num])) |
442 | video_unregister_device(dev->video_dev[chan_num]); | 442 | video_unregister_device(dev->video_dev[chan_num]); |
443 | else | 443 | else |
444 | video_device_release(dev->video_dev[chan_num]); | 444 | video_device_release(dev->video_dev[chan_num]); |
diff --git a/drivers/staging/cx25821/cx25821-video0.c b/drivers/staging/cx25821/cx25821-video0.c index 950fac1d7003..ad7a69129118 100644 --- a/drivers/staging/cx25821/cx25821-video0.c +++ b/drivers/staging/cx25821/cx25821-video0.c | |||
@@ -94,37 +94,21 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH00] | ||
109 | && h->video_dev[SRAM_CH00]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
128 | 112 | ||
129 | file->private_data = fh; | 113 | file->private_data = fh; |
130 | fh->dev = dev; | 114 | fh->dev = dev; |
@@ -444,7 +428,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
444 | struct video_device cx25821_video_template0 = { | 428 | struct video_device cx25821_video_template0 = { |
445 | .name = "cx25821-video", | 429 | .name = "cx25821-video", |
446 | .fops = &video_fops, | 430 | .fops = &video_fops, |
447 | .minor = -1, | ||
448 | .ioctl_ops = &video_ioctl_ops, | 431 | .ioctl_ops = &video_ioctl_ops, |
449 | .tvnorms = CX25821_NORMS, | 432 | .tvnorms = CX25821_NORMS, |
450 | .current_norm = V4L2_STD_NTSC_M, | 433 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video1.c b/drivers/staging/cx25821/cx25821-video1.c index a4dddc684adf..e3f3c4ac7908 100644 --- a/drivers/staging/cx25821/cx25821-video1.c +++ b/drivers/staging/cx25821/cx25821-video1.c | |||
@@ -94,37 +94,21 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH01] | ||
109 | && h->video_dev[SRAM_CH01]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
128 | 112 | ||
129 | file->private_data = fh; | 113 | file->private_data = fh; |
130 | fh->dev = dev; | 114 | fh->dev = dev; |
@@ -444,7 +428,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
444 | struct video_device cx25821_video_template1 = { | 428 | struct video_device cx25821_video_template1 = { |
445 | .name = "cx25821-video", | 429 | .name = "cx25821-video", |
446 | .fops = &video_fops, | 430 | .fops = &video_fops, |
447 | .minor = -1, | ||
448 | .ioctl_ops = &video_ioctl_ops, | 431 | .ioctl_ops = &video_ioctl_ops, |
449 | .tvnorms = CX25821_NORMS, | 432 | .tvnorms = CX25821_NORMS, |
450 | .current_norm = V4L2_STD_NTSC_M, | 433 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video2.c b/drivers/staging/cx25821/cx25821-video2.c index 8e04e253f5d9..36fb855a497e 100644 --- a/drivers/staging/cx25821/cx25821-video2.c +++ b/drivers/staging/cx25821/cx25821-video2.c | |||
@@ -94,37 +94,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH02] | ||
109 | && h->video_dev[SRAM_CH02]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
112 | |||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
130 | fh->type = type; | 115 | fh->type = type; |
@@ -445,7 +430,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
445 | struct video_device cx25821_video_template2 = { | 430 | struct video_device cx25821_video_template2 = { |
446 | .name = "cx25821-video", | 431 | .name = "cx25821-video", |
447 | .fops = &video_fops, | 432 | .fops = &video_fops, |
448 | .minor = -1, | ||
449 | .ioctl_ops = &video_ioctl_ops, | 433 | .ioctl_ops = &video_ioctl_ops, |
450 | .tvnorms = CX25821_NORMS, | 434 | .tvnorms = CX25821_NORMS, |
451 | .current_norm = V4L2_STD_NTSC_M, | 435 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video3.c b/drivers/staging/cx25821/cx25821-video3.c index 8801a8ead904..1e0f10abdbcd 100644 --- a/drivers/staging/cx25821/cx25821-video3.c +++ b/drivers/staging/cx25821/cx25821-video3.c | |||
@@ -94,37 +94,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH03] | ||
109 | && h->video_dev[SRAM_CH03]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
112 | |||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
130 | fh->type = type; | 115 | fh->type = type; |
@@ -444,7 +429,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
444 | struct video_device cx25821_video_template3 = { | 429 | struct video_device cx25821_video_template3 = { |
445 | .name = "cx25821-video", | 430 | .name = "cx25821-video", |
446 | .fops = &video_fops, | 431 | .fops = &video_fops, |
447 | .minor = -1, | ||
448 | .ioctl_ops = &video_ioctl_ops, | 432 | .ioctl_ops = &video_ioctl_ops, |
449 | .tvnorms = CX25821_NORMS, | 433 | .tvnorms = CX25821_NORMS, |
450 | .current_norm = V4L2_STD_NTSC_M, | 434 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video4.c b/drivers/staging/cx25821/cx25821-video4.c index ab0d747138ad..0cbe7a79d8c0 100644 --- a/drivers/staging/cx25821/cx25821-video4.c +++ b/drivers/staging/cx25821/cx25821-video4.c | |||
@@ -94,37 +94,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH04] | ||
109 | && h->video_dev[SRAM_CH04]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
112 | |||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
130 | fh->type = type; | 115 | fh->type = type; |
@@ -443,7 +428,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
443 | struct video_device cx25821_video_template4 = { | 428 | struct video_device cx25821_video_template4 = { |
444 | .name = "cx25821-video", | 429 | .name = "cx25821-video", |
445 | .fops = &video_fops, | 430 | .fops = &video_fops, |
446 | .minor = -1, | ||
447 | .ioctl_ops = &video_ioctl_ops, | 431 | .ioctl_ops = &video_ioctl_ops, |
448 | .tvnorms = CX25821_NORMS, | 432 | .tvnorms = CX25821_NORMS, |
449 | .current_norm = V4L2_STD_NTSC_M, | 433 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video5.c b/drivers/staging/cx25821/cx25821-video5.c index 7ef0b971f5cf..5dc08adc12e8 100644 --- a/drivers/staging/cx25821/cx25821-video5.c +++ b/drivers/staging/cx25821/cx25821-video5.c | |||
@@ -94,37 +94,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH05] | ||
109 | && h->video_dev[SRAM_CH05]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
112 | |||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
130 | fh->type = type; | 115 | fh->type = type; |
@@ -443,7 +428,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
443 | struct video_device cx25821_video_template5 = { | 428 | struct video_device cx25821_video_template5 = { |
444 | .name = "cx25821-video", | 429 | .name = "cx25821-video", |
445 | .fops = &video_fops, | 430 | .fops = &video_fops, |
446 | .minor = -1, | ||
447 | .ioctl_ops = &video_ioctl_ops, | 431 | .ioctl_ops = &video_ioctl_ops, |
448 | .tvnorms = CX25821_NORMS, | 432 | .tvnorms = CX25821_NORMS, |
449 | .current_norm = V4L2_STD_NTSC_M, | 433 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video6.c b/drivers/staging/cx25821/cx25821-video6.c index 3c41b49e2ea9..2938ad3ad3c5 100644 --- a/drivers/staging/cx25821/cx25821-video6.c +++ b/drivers/staging/cx25821/cx25821-video6.c | |||
@@ -94,37 +94,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->video_dev[SRAM_CH06] | ||
109 | && h->video_dev[SRAM_CH06]->minor == minor) { | ||
110 | dev = h; | ||
111 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (NULL == dev) { | ||
116 | unlock_kernel(); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
121 | 105 | ||
122 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
123 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
124 | if (NULL == fh) { | 108 | if (NULL == fh) |
125 | unlock_kernel(); | ||
126 | return -ENOMEM; | 109 | return -ENOMEM; |
127 | } | 110 | |
111 | lock_kernel(); | ||
112 | |||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
130 | fh->type = type; | 115 | fh->type = type; |
@@ -443,7 +428,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
443 | struct video_device cx25821_video_template6 = { | 428 | struct video_device cx25821_video_template6 = { |
444 | .name = "cx25821-video", | 429 | .name = "cx25821-video", |
445 | .fops = &video_fops, | 430 | .fops = &video_fops, |
446 | .minor = -1, | ||
447 | .ioctl_ops = &video_ioctl_ops, | 431 | .ioctl_ops = &video_ioctl_ops, |
448 | .tvnorms = CX25821_NORMS, | 432 | .tvnorms = CX25821_NORMS, |
449 | .current_norm = V4L2_STD_NTSC_M, | 433 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-video7.c b/drivers/staging/cx25821/cx25821-video7.c index 625c9b78a9cf..458e525d72af 100644 --- a/drivers/staging/cx25821/cx25821-video7.c +++ b/drivers/staging/cx25821/cx25821-video7.c | |||
@@ -93,37 +93,22 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
93 | 93 | ||
94 | static int video_open(struct file *file) | 94 | static int video_open(struct file *file) |
95 | { | 95 | { |
96 | int minor = video_devdata(file)->minor; | 96 | struct video_device *vdev = video_devdata(file); |
97 | struct cx25821_dev *h, *dev = NULL; | 97 | struct cx25821_dev *dev = video_drvdata(file); |
98 | struct cx25821_fh *fh; | 98 | struct cx25821_fh *fh; |
99 | struct list_head *list; | 99 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
100 | enum v4l2_buf_type type = 0; | ||
101 | u32 pix_format; | 100 | u32 pix_format; |
102 | 101 | ||
103 | lock_kernel(); | 102 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
104 | list_for_each(list, &cx25821_devlist) { | 103 | v4l2_type_names[type]); |
105 | h = list_entry(list, struct cx25821_dev, devlist); | ||
106 | |||
107 | if (h->video_dev[SRAM_CH07] | ||
108 | && h->video_dev[SRAM_CH07]->minor == minor) { | ||
109 | dev = h; | ||
110 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (NULL == dev) { | ||
115 | unlock_kernel(); | ||
116 | return -ENODEV; | ||
117 | } | ||
118 | |||
119 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
120 | 104 | ||
121 | /* allocate + initialize per filehandle data */ | 105 | /* allocate + initialize per filehandle data */ |
122 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 106 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
123 | if (NULL == fh) { | 107 | if (NULL == fh) |
124 | unlock_kernel(); | ||
125 | return -ENOMEM; | 108 | return -ENOMEM; |
126 | } | 109 | |
110 | lock_kernel(); | ||
111 | |||
127 | file->private_data = fh; | 112 | file->private_data = fh; |
128 | fh->dev = dev; | 113 | fh->dev = dev; |
129 | fh->type = type; | 114 | fh->type = type; |
@@ -442,7 +427,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
442 | struct video_device cx25821_video_template7 = { | 427 | struct video_device cx25821_video_template7 = { |
443 | .name = "cx25821-video", | 428 | .name = "cx25821-video", |
444 | .fops = &video_fops, | 429 | .fops = &video_fops, |
445 | .minor = -1, | ||
446 | .ioctl_ops = &video_ioctl_ops, | 430 | .ioctl_ops = &video_ioctl_ops, |
447 | .tvnorms = CX25821_NORMS, | 431 | .tvnorms = CX25821_NORMS, |
448 | .current_norm = V4L2_STD_NTSC_M, | 432 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-videoioctl.c b/drivers/staging/cx25821/cx25821-videoioctl.c index 2a312ce78c63..1da52b54a454 100644 --- a/drivers/staging/cx25821/cx25821-videoioctl.c +++ b/drivers/staging/cx25821/cx25821-videoioctl.c | |||
@@ -94,36 +94,21 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | u32 pix_format; | 101 | u32 pix_format; |
103 | 102 | ||
104 | lock_kernel(); | 103 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
105 | list_for_each(list, &cx25821_devlist) { | 104 | v4l2_type_names[type]); |
106 | h = list_entry(list, struct cx25821_dev, devlist); | ||
107 | |||
108 | if (h->ioctl_dev && h->ioctl_dev->minor == minor) { | ||
109 | dev = h; | ||
110 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (NULL == dev) { | ||
115 | unlock_kernel(); | ||
116 | return -ENODEV; | ||
117 | } | ||
118 | |||
119 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
120 | 105 | ||
121 | /* allocate + initialize per filehandle data */ | 106 | /* allocate + initialize per filehandle data */ |
122 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 107 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
123 | if (NULL == fh) { | 108 | if (NULL == fh) |
124 | unlock_kernel(); | ||
125 | return -ENOMEM; | 109 | return -ENOMEM; |
126 | } | 110 | |
111 | lock_kernel(); | ||
127 | 112 | ||
128 | file->private_data = fh; | 113 | file->private_data = fh; |
129 | fh->dev = dev; | 114 | fh->dev = dev; |
@@ -489,7 +474,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
489 | struct video_device cx25821_videoioctl_template = { | 474 | struct video_device cx25821_videoioctl_template = { |
490 | .name = "cx25821-videoioctl", | 475 | .name = "cx25821-videoioctl", |
491 | .fops = &video_fops, | 476 | .fops = &video_fops, |
492 | .minor = -1, | ||
493 | .ioctl_ops = &video_ioctl_ops, | 477 | .ioctl_ops = &video_ioctl_ops, |
494 | .tvnorms = CX25821_NORMS, | 478 | .tvnorms = CX25821_NORMS, |
495 | .current_norm = V4L2_STD_NTSC_M, | 479 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-vidups10.c b/drivers/staging/cx25821/cx25821-vidups10.c index 77b63b060405..b76d9f62c3d1 100644 --- a/drivers/staging/cx25821/cx25821-vidups10.c +++ b/drivers/staging/cx25821/cx25821-vidups10.c | |||
@@ -94,36 +94,20 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | 101 | ||
103 | lock_kernel(); | 102 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
104 | list_for_each(list, &cx25821_devlist) { | 103 | v4l2_type_names[type]); |
105 | h = list_entry(list, struct cx25821_dev, devlist); | ||
106 | |||
107 | if (h->video_dev[SRAM_CH10] | ||
108 | && h->video_dev[SRAM_CH10]->minor == minor) { | ||
109 | dev = h; | ||
110 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (NULL == dev) { | ||
115 | unlock_kernel(); | ||
116 | return -ENODEV; | ||
117 | } | ||
118 | |||
119 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
120 | 104 | ||
121 | /* allocate + initialize per filehandle data */ | 105 | /* allocate + initialize per filehandle data */ |
122 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 106 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
123 | if (NULL == fh) { | 107 | if (NULL == fh) |
124 | unlock_kernel(); | ||
125 | return -ENOMEM; | 108 | return -ENOMEM; |
126 | } | 109 | |
110 | lock_kernel(); | ||
127 | 111 | ||
128 | file->private_data = fh; | 112 | file->private_data = fh; |
129 | fh->dev = dev; | 113 | fh->dev = dev; |
@@ -428,7 +412,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
428 | struct video_device cx25821_video_template10 = { | 412 | struct video_device cx25821_video_template10 = { |
429 | .name = "cx25821-upstream10", | 413 | .name = "cx25821-upstream10", |
430 | .fops = &video_fops, | 414 | .fops = &video_fops, |
431 | .minor = -1, | ||
432 | .ioctl_ops = &video_ioctl_ops, | 415 | .ioctl_ops = &video_ioctl_ops, |
433 | .tvnorms = CX25821_NORMS, | 416 | .tvnorms = CX25821_NORMS, |
434 | .current_norm = V4L2_STD_NTSC_M, | 417 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/cx25821/cx25821-vidups9.c b/drivers/staging/cx25821/cx25821-vidups9.c index 75c8c1eed2da..1580da3b29aa 100644 --- a/drivers/staging/cx25821/cx25821-vidups9.c +++ b/drivers/staging/cx25821/cx25821-vidups9.c | |||
@@ -94,36 +94,20 @@ static struct videobuf_queue_ops cx25821_video_qops = { | |||
94 | 94 | ||
95 | static int video_open(struct file *file) | 95 | static int video_open(struct file *file) |
96 | { | 96 | { |
97 | int minor = video_devdata(file)->minor; | 97 | struct video_device *vdev = video_devdata(file); |
98 | struct cx25821_dev *h, *dev = NULL; | 98 | struct cx25821_dev *dev = video_drvdata(file); |
99 | struct cx25821_fh *fh; | 99 | struct cx25821_fh *fh; |
100 | struct list_head *list; | 100 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
101 | enum v4l2_buf_type type = 0; | ||
102 | 101 | ||
103 | lock_kernel(); | 102 | printk("open dev=%s type=%s\n", video_device_node_name(vdev), |
104 | list_for_each(list, &cx25821_devlist) { | 103 | v4l2_type_names[type]); |
105 | h = list_entry(list, struct cx25821_dev, devlist); | ||
106 | |||
107 | if (h->video_dev[SRAM_CH09] | ||
108 | && h->video_dev[SRAM_CH09]->minor == minor) { | ||
109 | dev = h; | ||
110 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (NULL == dev) { | ||
115 | unlock_kernel(); | ||
116 | return -ENODEV; | ||
117 | } | ||
118 | |||
119 | printk("open minor=%d type=%s\n", minor, v4l2_type_names[type]); | ||
120 | 104 | ||
121 | /* allocate + initialize per filehandle data */ | 105 | /* allocate + initialize per filehandle data */ |
122 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 106 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
123 | if (NULL == fh) { | 107 | if (NULL == fh) |
124 | unlock_kernel(); | ||
125 | return -ENOMEM; | 108 | return -ENOMEM; |
126 | } | 109 | |
110 | lock_kernel(); | ||
127 | 111 | ||
128 | file->private_data = fh; | 112 | file->private_data = fh; |
129 | fh->dev = dev; | 113 | fh->dev = dev; |
@@ -426,7 +410,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
426 | struct video_device cx25821_video_template9 = { | 410 | struct video_device cx25821_video_template9 = { |
427 | .name = "cx25821-upstream9", | 411 | .name = "cx25821-upstream9", |
428 | .fops = &video_fops, | 412 | .fops = &video_fops, |
429 | .minor = -1, | ||
430 | .ioctl_ops = &video_ioctl_ops, | 413 | .ioctl_ops = &video_ioctl_ops, |
431 | .tvnorms = CX25821_NORMS, | 414 | .tvnorms = CX25821_NORMS, |
432 | .current_norm = V4L2_STD_NTSC_M, | 415 | .current_norm = V4L2_STD_NTSC_M, |
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c index b18d8e2d4c5e..3af79242313e 100644 --- a/drivers/staging/go7007/go7007-v4l2.c +++ b/drivers/staging/go7007/go7007-v4l2.c | |||
@@ -1787,7 +1787,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1787 | static struct video_device go7007_template = { | 1787 | static struct video_device go7007_template = { |
1788 | .name = "go7007", | 1788 | .name = "go7007", |
1789 | .fops = &go7007_fops, | 1789 | .fops = &go7007_fops, |
1790 | .minor = -1, | ||
1791 | .release = go7007_vfl_release, | 1790 | .release = go7007_vfl_release, |
1792 | .ioctl_ops = &video_ioctl_ops, | 1791 | .ioctl_ops = &video_ioctl_ops, |
1793 | .tvnorms = V4L2_STD_ALL, | 1792 | .tvnorms = V4L2_STD_ALL, |
@@ -1817,8 +1816,8 @@ int go7007_v4l2_init(struct go7007 *go) | |||
1817 | } | 1816 | } |
1818 | video_set_drvdata(go->video_dev, go); | 1817 | video_set_drvdata(go->video_dev, go); |
1819 | ++go->ref_count; | 1818 | ++go->ref_count; |
1820 | printk(KERN_INFO "%s: registered device video%d [v4l2]\n", | 1819 | printk(KERN_INFO "%s: registered device %s [v4l2]\n", |
1821 | go->video_dev->name, go->video_dev->num); | 1820 | go->video_dev->name, video_device_node_name(go->video_dev)); |
1822 | 1821 | ||
1823 | return 0; | 1822 | return 0; |
1824 | } | 1823 | } |
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 5c774ab98252..73352f3739b5 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c | |||
@@ -80,7 +80,7 @@ | |||
80 | #include <linux/platform_device.h> | 80 | #include <linux/platform_device.h> |
81 | #include <linux/pm.h> | 81 | #include <linux/pm.h> |
82 | #include <linux/io.h> | 82 | #include <linux/io.h> |
83 | #include <linux/bitops.h> | 83 | #include <linux/bitmap.h> |
84 | 84 | ||
85 | #include <asm/irq.h> | 85 | #include <asm/irq.h> |
86 | #include <asm/system.h> | 86 | #include <asm/system.h> |
@@ -190,10 +190,8 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, | |||
190 | struct isp1362_ep *ep, u16 len) | 190 | struct isp1362_ep *ep, u16 len) |
191 | { | 191 | { |
192 | int ptd_offset = -EINVAL; | 192 | int ptd_offset = -EINVAL; |
193 | int index; | ||
194 | int num_ptds = ((len + PTD_HEADER_SIZE - 1) / epq->blk_size) + 1; | 193 | int num_ptds = ((len + PTD_HEADER_SIZE - 1) / epq->blk_size) + 1; |
195 | int found = -1; | 194 | int found; |
196 | int last = -1; | ||
197 | 195 | ||
198 | BUG_ON(len > epq->buf_size); | 196 | BUG_ON(len > epq->buf_size); |
199 | 197 | ||
@@ -205,20 +203,9 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, | |||
205 | epq->name, len, epq->blk_size, num_ptds, epq->buf_map, epq->skip_map); | 203 | epq->name, len, epq->blk_size, num_ptds, epq->buf_map, epq->skip_map); |
206 | BUG_ON(ep->num_ptds != 0); | 204 | BUG_ON(ep->num_ptds != 0); |
207 | 205 | ||
208 | for (index = 0; index <= epq->buf_count - num_ptds; index++) { | 206 | found = bitmap_find_next_zero_area(&epq->buf_map, epq->buf_count, 0, |
209 | if (test_bit(index, &epq->buf_map)) | 207 | num_ptds, 0); |
210 | continue; | 208 | if (found >= epq->buf_count) |
211 | found = index; | ||
212 | for (last = index + 1; last < index + num_ptds; last++) { | ||
213 | if (test_bit(last, &epq->buf_map)) { | ||
214 | found = -1; | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | if (found >= 0) | ||
219 | break; | ||
220 | } | ||
221 | if (found < 0) | ||
222 | return -EOVERFLOW; | 209 | return -EOVERFLOW; |
223 | 210 | ||
224 | DBG(1, "%s: Found %d PTDs[%d] for %d/%d byte\n", __func__, | 211 | DBG(1, "%s: Found %d PTDs[%d] for %d/%d byte\n", __func__, |
@@ -230,8 +217,7 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, | |||
230 | epq->buf_avail -= num_ptds; | 217 | epq->buf_avail -= num_ptds; |
231 | BUG_ON(epq->buf_avail > epq->buf_count); | 218 | BUG_ON(epq->buf_avail > epq->buf_count); |
232 | ep->ptd_index = found; | 219 | ep->ptd_index = found; |
233 | for (index = found; index < last; index++) | 220 | bitmap_set(&epq->buf_map, found, num_ptds); |
234 | __set_bit(index, &epq->buf_map); | ||
235 | DBG(1, "%s: Done %s PTD[%d] $%04x, avail %d count %d claimed %d %08lx:%08lx\n", | 221 | DBG(1, "%s: Done %s PTD[%d] $%04x, avail %d count %d claimed %d %08lx:%08lx\n", |
236 | __func__, epq->name, ep->ptd_index, ep->ptd_offset, | 222 | __func__, epq->name, ep->ptd_index, ep->ptd_offset, |
237 | epq->buf_avail, epq->buf_count, num_ptds, epq->buf_map, epq->skip_map); | 223 | epq->buf_avail, epq->buf_count, num_ptds, epq->buf_map, epq->skip_map); |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 99c0df1c7ebf..5a5c303a6373 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -614,6 +614,21 @@ config FB_BFIN_T350MCQB | |||
614 | This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI | 614 | This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI |
615 | It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. | 615 | It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. |
616 | 616 | ||
617 | config FB_BFIN_LQ035Q1 | ||
618 | tristate "SHARP LQ035Q1DH02 TFT LCD" | ||
619 | depends on FB && BLACKFIN && SPI | ||
620 | select FB_CFB_FILLRECT | ||
621 | select FB_CFB_COPYAREA | ||
622 | select FB_CFB_IMAGEBLIT | ||
623 | select BFIN_GPTIMERS | ||
624 | help | ||
625 | This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on | ||
626 | the Blackfin Landscape LCD EZ-Extender Card. | ||
627 | This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI | ||
628 | It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. | ||
629 | |||
630 | To compile this driver as a module, choose M here: the | ||
631 | module will be called bfin-lq035q1-fb. | ||
617 | 632 | ||
618 | config FB_STI | 633 | config FB_STI |
619 | tristate "HP STI frame buffer device support" | 634 | tristate "HP STI frame buffer device support" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0f8da331ba0f..4ecb30c4f3f2 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -137,6 +137,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o | |||
137 | obj-$(CONFIG_FB_VGA16) += vga16fb.o | 137 | obj-$(CONFIG_FB_VGA16) += vga16fb.o |
138 | obj-$(CONFIG_FB_OF) += offb.o | 138 | obj-$(CONFIG_FB_OF) += offb.o |
139 | obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o | 139 | obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o |
140 | obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o | ||
140 | obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o | 141 | obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o |
141 | obj-$(CONFIG_FB_MX3) += mx3fb.o | 142 | obj-$(CONFIG_FB_MX3) += mx3fb.o |
142 | obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o | 143 | obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o |
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index b7687c55fe16..2051c9dc813b 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c | |||
@@ -2245,6 +2245,9 @@ static int ext_setcolreg(unsigned int regno, unsigned int red, | |||
2245 | if (regno > 255) | 2245 | if (regno > 255) |
2246 | return 1; | 2246 | return 1; |
2247 | 2247 | ||
2248 | if (regno > 255) | ||
2249 | return 1; | ||
2250 | |||
2248 | switch (external_card_type) { | 2251 | switch (external_card_type) { |
2249 | case IS_VGA: | 2252 | case IS_VGA: |
2250 | OUTB(0x3c8, regno); | 2253 | OUTB(0x3c8, regno); |
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 000000000000..b690c269784a --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c | |||
@@ -0,0 +1,826 @@ | |||
1 | /* | ||
2 | * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 | ||
3 | * | ||
4 | * Copyright 2008-2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #define DRIVER_NAME "bfin-lq035q1" | ||
9 | #define pr_fmt(fmt) DRIVER_NAME ": " fmt | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/fb.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/backlight.h> | ||
21 | #include <linux/lcd.h> | ||
22 | #include <linux/dma-mapping.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/spi/spi.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | |||
27 | #include <asm/blackfin.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/dma.h> | ||
30 | #include <asm/portmux.h> | ||
31 | #include <asm/gptimers.h> | ||
32 | |||
33 | #include <asm/bfin-lq035q1.h> | ||
34 | |||
35 | #if defined(BF533_FAMILY) || defined(BF538_FAMILY) | ||
36 | #define TIMER_HSYNC_id TIMER1_id | ||
37 | #define TIMER_HSYNCbit TIMER1bit | ||
38 | #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 | ||
39 | #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 | ||
40 | #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 | ||
41 | |||
42 | #define TIMER_VSYNC_id TIMER2_id | ||
43 | #define TIMER_VSYNCbit TIMER2bit | ||
44 | #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 | ||
45 | #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 | ||
46 | #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 | ||
47 | #else | ||
48 | #define TIMER_HSYNC_id TIMER0_id | ||
49 | #define TIMER_HSYNCbit TIMER0bit | ||
50 | #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 | ||
51 | #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 | ||
52 | #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 | ||
53 | |||
54 | #define TIMER_VSYNC_id TIMER1_id | ||
55 | #define TIMER_VSYNCbit TIMER1bit | ||
56 | #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 | ||
57 | #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 | ||
58 | #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 | ||
59 | #endif | ||
60 | |||
61 | #define LCD_X_RES 320 /* Horizontal Resolution */ | ||
62 | #define LCD_Y_RES 240 /* Vertical Resolution */ | ||
63 | #define DMA_BUS_SIZE 16 | ||
64 | |||
65 | #define USE_RGB565_16_BIT_PPI | ||
66 | |||
67 | #ifdef USE_RGB565_16_BIT_PPI | ||
68 | #define LCD_BPP 16 /* Bit Per Pixel */ | ||
69 | #define CLOCKS_PER_PIX 1 | ||
70 | #define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ | ||
71 | #endif | ||
72 | |||
73 | /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) | ||
74 | * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 | ||
75 | */ | ||
76 | |||
77 | #ifdef USE_RGB565_8_BIT_PPI | ||
78 | #define LCD_BPP 16 /* Bit Per Pixel */ | ||
79 | #define CLOCKS_PER_PIX 2 | ||
80 | #define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ | ||
81 | #endif | ||
82 | |||
83 | #ifdef USE_RGB888_8_BIT_PPI | ||
84 | #define LCD_BPP 24 /* Bit Per Pixel */ | ||
85 | #define CLOCKS_PER_PIX 3 | ||
86 | #define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ | ||
87 | #endif | ||
88 | |||
89 | /* | ||
90 | * HS and VS timing parameters (all in number of PPI clk ticks) | ||
91 | */ | ||
92 | |||
93 | #define U_LINE 4 /* Blanking Lines */ | ||
94 | |||
95 | #define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ | ||
96 | #define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ | ||
97 | #define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ | ||
98 | #define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ | ||
99 | |||
100 | #define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ | ||
101 | #define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ | ||
102 | #define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ | ||
103 | |||
104 | #define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) | ||
105 | |||
106 | #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 | ||
107 | |||
108 | #define PPI_TX_MODE 0x2 | ||
109 | #define PPI_XFER_TYPE_11 0xC | ||
110 | #define PPI_PORT_CFG_01 0x10 | ||
111 | #define PPI_POLS_1 0x8000 | ||
112 | |||
113 | #if (CLOCKS_PER_PIX > 1) | ||
114 | #define PPI_PMODE (DLEN_8 | PACK_EN) | ||
115 | #else | ||
116 | #define PPI_PMODE (DLEN_16) | ||
117 | #endif | ||
118 | |||
119 | #define LQ035_INDEX 0x74 | ||
120 | #define LQ035_DATA 0x76 | ||
121 | |||
122 | #define LQ035_DRIVER_OUTPUT_CTL 0x1 | ||
123 | #define LQ035_SHUT_CTL 0x11 | ||
124 | |||
125 | #define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) | ||
126 | #define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) | ||
127 | |||
128 | #define LQ035_SHUT (1 << 0) /* Shutdown */ | ||
129 | #define LQ035_ON (0 << 0) /* Shutdown */ | ||
130 | |||
131 | struct bfin_lq035q1fb_info { | ||
132 | struct fb_info *fb; | ||
133 | struct device *dev; | ||
134 | struct spi_driver spidrv; | ||
135 | struct bfin_lq035q1fb_disp_info *disp_info; | ||
136 | unsigned char *fb_buffer; /* RGB Buffer */ | ||
137 | dma_addr_t dma_handle; | ||
138 | int lq035_open_cnt; | ||
139 | int irq; | ||
140 | spinlock_t lock; /* lock */ | ||
141 | u32 pseudo_pal[16]; | ||
142 | }; | ||
143 | |||
144 | static int nocursor; | ||
145 | module_param(nocursor, int, 0644); | ||
146 | MODULE_PARM_DESC(nocursor, "cursor enable/disable"); | ||
147 | |||
148 | struct spi_control { | ||
149 | unsigned short mode; | ||
150 | }; | ||
151 | |||
152 | static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) | ||
153 | { | ||
154 | int ret; | ||
155 | u8 regs[3] = { LQ035_INDEX, 0, 0 }; | ||
156 | u8 dat[3] = { LQ035_DATA, 0, 0 }; | ||
157 | |||
158 | if (!spi) | ||
159 | return -ENODEV; | ||
160 | |||
161 | regs[2] = reg; | ||
162 | dat[1] = value >> 8; | ||
163 | dat[2] = value & 0xFF; | ||
164 | |||
165 | ret = spi_write(spi, regs, ARRAY_SIZE(regs)); | ||
166 | ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int __devinit lq035q1_spidev_probe(struct spi_device *spi) | ||
171 | { | ||
172 | int ret; | ||
173 | struct spi_control *ctl; | ||
174 | struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, | ||
175 | struct bfin_lq035q1fb_info, | ||
176 | spidrv.driver); | ||
177 | |||
178 | ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); | ||
179 | |||
180 | if (!ctl) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | ctl->mode = (info->disp_info->mode & | ||
184 | LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; | ||
185 | |||
186 | ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); | ||
187 | ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); | ||
188 | if (ret) | ||
189 | return ret; | ||
190 | |||
191 | spi_set_drvdata(spi, ctl); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int lq035q1_spidev_remove(struct spi_device *spi) | ||
197 | { | ||
198 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); | ||
199 | } | ||
200 | |||
201 | #ifdef CONFIG_PM | ||
202 | static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) | ||
203 | { | ||
204 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); | ||
205 | } | ||
206 | |||
207 | static int lq035q1_spidev_resume(struct spi_device *spi) | ||
208 | { | ||
209 | int ret; | ||
210 | struct spi_control *ctl = spi_get_drvdata(spi); | ||
211 | |||
212 | ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | |||
216 | return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); | ||
217 | } | ||
218 | #else | ||
219 | # define lq035q1_spidev_suspend NULL | ||
220 | # define lq035q1_spidev_resume NULL | ||
221 | #endif | ||
222 | |||
223 | /* Power down all displays on reboot, poweroff or halt */ | ||
224 | static void lq035q1_spidev_shutdown(struct spi_device *spi) | ||
225 | { | ||
226 | lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); | ||
227 | } | ||
228 | |||
229 | static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) | ||
230 | { | ||
231 | if (info->disp_info->use_bl) | ||
232 | gpio_set_value(info->disp_info->gpio_bl, arg); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) | ||
238 | { | ||
239 | bfin_write_PPI_DELAY(H_START); | ||
240 | bfin_write_PPI_COUNT(H_ACTPIX - 1); | ||
241 | bfin_write_PPI_FRAME(V_LINES); | ||
242 | |||
243 | bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ | ||
244 | PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ | ||
245 | PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ | ||
246 | PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ | ||
247 | PPI_POLS_1); /* faling edge syncs POLS */ | ||
248 | } | ||
249 | |||
250 | static inline void bfin_lq035q1_disable_ppi(void) | ||
251 | { | ||
252 | bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); | ||
253 | } | ||
254 | |||
255 | static inline void bfin_lq035q1_enable_ppi(void) | ||
256 | { | ||
257 | bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); | ||
258 | } | ||
259 | |||
260 | static void bfin_lq035q1_start_timers(void) | ||
261 | { | ||
262 | enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); | ||
263 | } | ||
264 | |||
265 | static void bfin_lq035q1_stop_timers(void) | ||
266 | { | ||
267 | disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); | ||
268 | |||
269 | set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | | ||
270 | TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | | ||
271 | TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); | ||
272 | |||
273 | } | ||
274 | |||
275 | static void bfin_lq035q1_init_timers(void) | ||
276 | { | ||
277 | |||
278 | bfin_lq035q1_stop_timers(); | ||
279 | |||
280 | set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); | ||
281 | set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); | ||
282 | set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | ||
283 | TIMER_TIN_SEL | TIMER_CLK_SEL| | ||
284 | TIMER_EMU_RUN); | ||
285 | |||
286 | set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); | ||
287 | set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); | ||
288 | set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | ||
289 | TIMER_TIN_SEL | TIMER_CLK_SEL | | ||
290 | TIMER_EMU_RUN); | ||
291 | |||
292 | } | ||
293 | |||
294 | static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) | ||
295 | { | ||
296 | |||
297 | set_dma_config(CH_PPI, | ||
298 | set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, | ||
299 | INTR_DISABLE, DIMENSION_2D, | ||
300 | DATA_SIZE_16, | ||
301 | DMA_NOSYNC_KEEP_DMA_BUF)); | ||
302 | set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); | ||
303 | set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); | ||
304 | set_dma_y_count(CH_PPI, V_LINES); | ||
305 | |||
306 | set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); | ||
307 | set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); | ||
308 | |||
309 | } | ||
310 | |||
311 | #if (CLOCKS_PER_PIX == 1) | ||
312 | static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | ||
313 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, | ||
314 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, | ||
315 | P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, | ||
316 | P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, | ||
317 | P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, | ||
318 | P_PPI0_D15, 0}; | ||
319 | #else | ||
320 | static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | ||
321 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, | ||
322 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, | ||
323 | P_PPI0_D6, P_PPI0_D7, 0}; | ||
324 | #endif | ||
325 | |||
326 | static inline void bfin_lq035q1_free_ports(void) | ||
327 | { | ||
328 | peripheral_free_list(ppi0_req_16); | ||
329 | if (ANOMALY_05000400) | ||
330 | gpio_free(P_IDENT(P_PPI0_FS3)); | ||
331 | } | ||
332 | |||
333 | static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) | ||
334 | { | ||
335 | /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: | ||
336 | * Drive PPI_FS3 Low | ||
337 | */ | ||
338 | if (ANOMALY_05000400) { | ||
339 | int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); | ||
340 | if (ret) | ||
341 | return ret; | ||
342 | gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); | ||
343 | } | ||
344 | |||
345 | if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { | ||
346 | dev_err(&pdev->dev, "requesting peripherals failed\n"); | ||
347 | return -EFAULT; | ||
348 | } | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int bfin_lq035q1_fb_open(struct fb_info *info, int user) | ||
354 | { | ||
355 | struct bfin_lq035q1fb_info *fbi = info->par; | ||
356 | |||
357 | spin_lock(&fbi->lock); | ||
358 | fbi->lq035_open_cnt++; | ||
359 | |||
360 | if (fbi->lq035_open_cnt <= 1) { | ||
361 | |||
362 | bfin_lq035q1_disable_ppi(); | ||
363 | SSYNC(); | ||
364 | |||
365 | bfin_lq035q1_config_dma(fbi); | ||
366 | bfin_lq035q1_config_ppi(fbi); | ||
367 | bfin_lq035q1_init_timers(); | ||
368 | |||
369 | /* start dma */ | ||
370 | enable_dma(CH_PPI); | ||
371 | bfin_lq035q1_enable_ppi(); | ||
372 | bfin_lq035q1_start_timers(); | ||
373 | lq035q1_backlight(fbi, 1); | ||
374 | } | ||
375 | |||
376 | spin_unlock(&fbi->lock); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int bfin_lq035q1_fb_release(struct fb_info *info, int user) | ||
382 | { | ||
383 | struct bfin_lq035q1fb_info *fbi = info->par; | ||
384 | |||
385 | spin_lock(&fbi->lock); | ||
386 | |||
387 | fbi->lq035_open_cnt--; | ||
388 | |||
389 | if (fbi->lq035_open_cnt <= 0) { | ||
390 | lq035q1_backlight(fbi, 0); | ||
391 | bfin_lq035q1_disable_ppi(); | ||
392 | SSYNC(); | ||
393 | disable_dma(CH_PPI); | ||
394 | bfin_lq035q1_stop_timers(); | ||
395 | } | ||
396 | |||
397 | spin_unlock(&fbi->lock); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, | ||
403 | struct fb_info *info) | ||
404 | { | ||
405 | switch (var->bits_per_pixel) { | ||
406 | #if (LCD_BPP == 24) | ||
407 | case 24:/* TRUECOLOUR, 16m */ | ||
408 | #else | ||
409 | case 16:/* DIRECTCOLOUR, 64k */ | ||
410 | #endif | ||
411 | var->red.offset = info->var.red.offset; | ||
412 | var->green.offset = info->var.green.offset; | ||
413 | var->blue.offset = info->var.blue.offset; | ||
414 | var->red.length = info->var.red.length; | ||
415 | var->green.length = info->var.green.length; | ||
416 | var->blue.length = info->var.blue.length; | ||
417 | var->transp.offset = 0; | ||
418 | var->transp.length = 0; | ||
419 | var->transp.msb_right = 0; | ||
420 | var->red.msb_right = 0; | ||
421 | var->green.msb_right = 0; | ||
422 | var->blue.msb_right = 0; | ||
423 | break; | ||
424 | default: | ||
425 | pr_debug("%s: depth not supported: %u BPP\n", __func__, | ||
426 | var->bits_per_pixel); | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | |||
430 | if (info->var.xres != var->xres || info->var.yres != var->yres || | ||
431 | info->var.xres_virtual != var->xres_virtual || | ||
432 | info->var.yres_virtual != var->yres_virtual) { | ||
433 | pr_debug("%s: Resolution not supported: X%u x Y%u \n", | ||
434 | __func__, var->xres, var->yres); | ||
435 | return -EINVAL; | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * Memory limit | ||
440 | */ | ||
441 | |||
442 | if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { | ||
443 | pr_debug("%s: Memory Limit requested yres_virtual = %u\n", | ||
444 | __func__, var->yres_virtual); | ||
445 | return -ENOMEM; | ||
446 | } | ||
447 | |||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) | ||
453 | { | ||
454 | if (nocursor) | ||
455 | return 0; | ||
456 | else | ||
457 | return -EINVAL; /* just to force soft_cursor() call */ | ||
458 | } | ||
459 | |||
460 | static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, | ||
461 | u_int blue, u_int transp, | ||
462 | struct fb_info *info) | ||
463 | { | ||
464 | if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) | ||
465 | return -EINVAL; | ||
466 | |||
467 | if (info->var.grayscale) { | ||
468 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
469 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
470 | } | ||
471 | |||
472 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
473 | |||
474 | u32 value; | ||
475 | /* Place color in the pseudopalette */ | ||
476 | if (regno > 16) | ||
477 | return -EINVAL; | ||
478 | |||
479 | red >>= (16 - info->var.red.length); | ||
480 | green >>= (16 - info->var.green.length); | ||
481 | blue >>= (16 - info->var.blue.length); | ||
482 | |||
483 | value = (red << info->var.red.offset) | | ||
484 | (green << info->var.green.offset) | | ||
485 | (blue << info->var.blue.offset); | ||
486 | value &= 0xFFFFFF; | ||
487 | |||
488 | ((u32 *) (info->pseudo_palette))[regno] = value; | ||
489 | |||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static struct fb_ops bfin_lq035q1_fb_ops = { | ||
496 | .owner = THIS_MODULE, | ||
497 | .fb_open = bfin_lq035q1_fb_open, | ||
498 | .fb_release = bfin_lq035q1_fb_release, | ||
499 | .fb_check_var = bfin_lq035q1_fb_check_var, | ||
500 | .fb_fillrect = cfb_fillrect, | ||
501 | .fb_copyarea = cfb_copyarea, | ||
502 | .fb_imageblit = cfb_imageblit, | ||
503 | .fb_cursor = bfin_lq035q1_fb_cursor, | ||
504 | .fb_setcolreg = bfin_lq035q1_fb_setcolreg, | ||
505 | }; | ||
506 | |||
507 | static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) | ||
508 | { | ||
509 | /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ | ||
510 | |||
511 | u16 status = bfin_read_PPI_STATUS(); | ||
512 | bfin_write_PPI_STATUS(-1); | ||
513 | |||
514 | if (status) { | ||
515 | bfin_lq035q1_disable_ppi(); | ||
516 | disable_dma(CH_PPI); | ||
517 | |||
518 | /* start dma */ | ||
519 | enable_dma(CH_PPI); | ||
520 | bfin_lq035q1_enable_ppi(); | ||
521 | bfin_write_PPI_STATUS(-1); | ||
522 | } | ||
523 | |||
524 | return IRQ_HANDLED; | ||
525 | } | ||
526 | |||
527 | static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | ||
528 | { | ||
529 | struct bfin_lq035q1fb_info *info; | ||
530 | struct fb_info *fbinfo; | ||
531 | int ret; | ||
532 | |||
533 | ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); | ||
534 | if (ret < 0) { | ||
535 | dev_err(&pdev->dev, "PPI DMA unavailable\n"); | ||
536 | goto out1; | ||
537 | } | ||
538 | |||
539 | fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); | ||
540 | if (!fbinfo) { | ||
541 | ret = -ENOMEM; | ||
542 | goto out2; | ||
543 | } | ||
544 | |||
545 | info = fbinfo->par; | ||
546 | info->fb = fbinfo; | ||
547 | info->dev = &pdev->dev; | ||
548 | |||
549 | info->disp_info = pdev->dev.platform_data; | ||
550 | |||
551 | platform_set_drvdata(pdev, fbinfo); | ||
552 | |||
553 | strcpy(fbinfo->fix.id, DRIVER_NAME); | ||
554 | |||
555 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | ||
556 | fbinfo->fix.type_aux = 0; | ||
557 | fbinfo->fix.xpanstep = 0; | ||
558 | fbinfo->fix.ypanstep = 0; | ||
559 | fbinfo->fix.ywrapstep = 0; | ||
560 | fbinfo->fix.accel = FB_ACCEL_NONE; | ||
561 | fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; | ||
562 | |||
563 | fbinfo->var.nonstd = 0; | ||
564 | fbinfo->var.activate = FB_ACTIVATE_NOW; | ||
565 | fbinfo->var.height = -1; | ||
566 | fbinfo->var.width = -1; | ||
567 | fbinfo->var.accel_flags = 0; | ||
568 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; | ||
569 | |||
570 | fbinfo->var.xres = LCD_X_RES; | ||
571 | fbinfo->var.xres_virtual = LCD_X_RES; | ||
572 | fbinfo->var.yres = LCD_Y_RES; | ||
573 | fbinfo->var.yres_virtual = LCD_Y_RES; | ||
574 | fbinfo->var.bits_per_pixel = LCD_BPP; | ||
575 | |||
576 | if (info->disp_info->mode & LQ035_BGR) { | ||
577 | #if (LCD_BPP == 24) | ||
578 | fbinfo->var.red.offset = 0; | ||
579 | fbinfo->var.green.offset = 8; | ||
580 | fbinfo->var.blue.offset = 16; | ||
581 | #else | ||
582 | fbinfo->var.red.offset = 0; | ||
583 | fbinfo->var.green.offset = 5; | ||
584 | fbinfo->var.blue.offset = 11; | ||
585 | #endif | ||
586 | } else { | ||
587 | #if (LCD_BPP == 24) | ||
588 | fbinfo->var.red.offset = 16; | ||
589 | fbinfo->var.green.offset = 8; | ||
590 | fbinfo->var.blue.offset = 0; | ||
591 | #else | ||
592 | fbinfo->var.red.offset = 11; | ||
593 | fbinfo->var.green.offset = 5; | ||
594 | fbinfo->var.blue.offset = 0; | ||
595 | #endif | ||
596 | } | ||
597 | |||
598 | fbinfo->var.transp.offset = 0; | ||
599 | |||
600 | #if (LCD_BPP == 24) | ||
601 | fbinfo->var.red.length = 8; | ||
602 | fbinfo->var.green.length = 8; | ||
603 | fbinfo->var.blue.length = 8; | ||
604 | #else | ||
605 | fbinfo->var.red.length = 5; | ||
606 | fbinfo->var.green.length = 6; | ||
607 | fbinfo->var.blue.length = 5; | ||
608 | #endif | ||
609 | |||
610 | fbinfo->var.transp.length = 0; | ||
611 | |||
612 | fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 | ||
613 | + ACTIVE_VIDEO_MEM_OFFSET; | ||
614 | |||
615 | fbinfo->fix.line_length = fbinfo->var.xres_virtual * | ||
616 | fbinfo->var.bits_per_pixel / 8; | ||
617 | |||
618 | |||
619 | fbinfo->fbops = &bfin_lq035q1_fb_ops; | ||
620 | fbinfo->flags = FBINFO_FLAG_DEFAULT; | ||
621 | |||
622 | info->fb_buffer = | ||
623 | dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, | ||
624 | GFP_KERNEL); | ||
625 | |||
626 | if (NULL == info->fb_buffer) { | ||
627 | dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); | ||
628 | ret = -ENOMEM; | ||
629 | goto out3; | ||
630 | } | ||
631 | |||
632 | fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | ||
633 | fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | ||
634 | |||
635 | fbinfo->fbops = &bfin_lq035q1_fb_ops; | ||
636 | |||
637 | fbinfo->pseudo_palette = &info->pseudo_pal; | ||
638 | |||
639 | ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); | ||
640 | if (ret < 0) { | ||
641 | dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", | ||
642 | BFIN_LCD_NBR_PALETTE_ENTRIES); | ||
643 | goto out4; | ||
644 | } | ||
645 | |||
646 | ret = bfin_lq035q1_request_ports(pdev); | ||
647 | if (ret) { | ||
648 | dev_err(&pdev->dev, "couldn't request gpio port\n"); | ||
649 | goto out6; | ||
650 | } | ||
651 | |||
652 | info->irq = platform_get_irq(pdev, 0); | ||
653 | if (info->irq < 0) { | ||
654 | ret = -EINVAL; | ||
655 | goto out7; | ||
656 | } | ||
657 | |||
658 | ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, | ||
659 | DRIVER_NAME" PPI ERROR", info); | ||
660 | if (ret < 0) { | ||
661 | dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); | ||
662 | goto out7; | ||
663 | } | ||
664 | |||
665 | info->spidrv.driver.name = DRIVER_NAME"-spi"; | ||
666 | info->spidrv.probe = lq035q1_spidev_probe; | ||
667 | info->spidrv.remove = __devexit_p(lq035q1_spidev_remove); | ||
668 | info->spidrv.shutdown = lq035q1_spidev_shutdown; | ||
669 | info->spidrv.suspend = lq035q1_spidev_suspend; | ||
670 | info->spidrv.resume = lq035q1_spidev_resume; | ||
671 | |||
672 | ret = spi_register_driver(&info->spidrv); | ||
673 | if (ret < 0) { | ||
674 | dev_err(&pdev->dev, "couldn't register SPI Interface\n"); | ||
675 | goto out8; | ||
676 | } | ||
677 | |||
678 | if (info->disp_info->use_bl) { | ||
679 | ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); | ||
680 | |||
681 | if (ret) { | ||
682 | dev_err(&pdev->dev, "failed to request GPIO %d\n", | ||
683 | info->disp_info->gpio_bl); | ||
684 | goto out9; | ||
685 | } | ||
686 | gpio_direction_output(info->disp_info->gpio_bl, 0); | ||
687 | } | ||
688 | |||
689 | ret = register_framebuffer(fbinfo); | ||
690 | if (ret < 0) { | ||
691 | dev_err(&pdev->dev, "unable to register framebuffer\n"); | ||
692 | goto out10; | ||
693 | } | ||
694 | |||
695 | dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", | ||
696 | LCD_X_RES, LCD_Y_RES, LCD_BPP); | ||
697 | |||
698 | return 0; | ||
699 | |||
700 | out10: | ||
701 | if (info->disp_info->use_bl) | ||
702 | gpio_free(info->disp_info->gpio_bl); | ||
703 | out9: | ||
704 | spi_unregister_driver(&info->spidrv); | ||
705 | out8: | ||
706 | free_irq(info->irq, info); | ||
707 | out7: | ||
708 | bfin_lq035q1_free_ports(); | ||
709 | out6: | ||
710 | fb_dealloc_cmap(&fbinfo->cmap); | ||
711 | out4: | ||
712 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
713 | info->dma_handle); | ||
714 | out3: | ||
715 | framebuffer_release(fbinfo); | ||
716 | out2: | ||
717 | free_dma(CH_PPI); | ||
718 | out1: | ||
719 | platform_set_drvdata(pdev, NULL); | ||
720 | |||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) | ||
725 | { | ||
726 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | ||
727 | struct bfin_lq035q1fb_info *info = fbinfo->par; | ||
728 | |||
729 | if (info->disp_info->use_bl) | ||
730 | gpio_free(info->disp_info->gpio_bl); | ||
731 | |||
732 | spi_unregister_driver(&info->spidrv); | ||
733 | |||
734 | unregister_framebuffer(fbinfo); | ||
735 | |||
736 | free_dma(CH_PPI); | ||
737 | free_irq(info->irq, info); | ||
738 | |||
739 | if (info->fb_buffer != NULL) | ||
740 | dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, | ||
741 | info->dma_handle); | ||
742 | |||
743 | fb_dealloc_cmap(&fbinfo->cmap); | ||
744 | |||
745 | bfin_lq035q1_free_ports(); | ||
746 | |||
747 | platform_set_drvdata(pdev, NULL); | ||
748 | framebuffer_release(fbinfo); | ||
749 | |||
750 | dev_info(&pdev->dev, "unregistered LCD driver\n"); | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | #ifdef CONFIG_PM | ||
756 | static int bfin_lq035q1_suspend(struct device *dev) | ||
757 | { | ||
758 | struct fb_info *fbinfo = dev_get_drvdata(dev); | ||
759 | struct bfin_lq035q1fb_info *info = fbinfo->par; | ||
760 | |||
761 | if (info->lq035_open_cnt) { | ||
762 | lq035q1_backlight(info, 0); | ||
763 | bfin_lq035q1_disable_ppi(); | ||
764 | SSYNC(); | ||
765 | disable_dma(CH_PPI); | ||
766 | bfin_lq035q1_stop_timers(); | ||
767 | bfin_write_PPI_STATUS(-1); | ||
768 | } | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int bfin_lq035q1_resume(struct device *dev) | ||
774 | { | ||
775 | struct fb_info *fbinfo = dev_get_drvdata(dev); | ||
776 | struct bfin_lq035q1fb_info *info = fbinfo->par; | ||
777 | |||
778 | if (info->lq035_open_cnt) { | ||
779 | bfin_lq035q1_disable_ppi(); | ||
780 | SSYNC(); | ||
781 | |||
782 | bfin_lq035q1_config_dma(info); | ||
783 | bfin_lq035q1_config_ppi(info); | ||
784 | bfin_lq035q1_init_timers(); | ||
785 | |||
786 | /* start dma */ | ||
787 | enable_dma(CH_PPI); | ||
788 | bfin_lq035q1_enable_ppi(); | ||
789 | bfin_lq035q1_start_timers(); | ||
790 | lq035q1_backlight(info, 1); | ||
791 | } | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { | ||
797 | .suspend = bfin_lq035q1_suspend, | ||
798 | .resume = bfin_lq035q1_resume, | ||
799 | }; | ||
800 | #endif | ||
801 | |||
802 | static struct platform_driver bfin_lq035q1_driver = { | ||
803 | .probe = bfin_lq035q1_probe, | ||
804 | .remove = __devexit_p(bfin_lq035q1_remove), | ||
805 | .driver = { | ||
806 | .name = DRIVER_NAME, | ||
807 | #ifdef CONFIG_PM | ||
808 | .pm = &bfin_lq035q1_dev_pm_ops, | ||
809 | #endif | ||
810 | }, | ||
811 | }; | ||
812 | |||
813 | static int __init bfin_lq035q1_driver_init(void) | ||
814 | { | ||
815 | return platform_driver_register(&bfin_lq035q1_driver); | ||
816 | } | ||
817 | module_init(bfin_lq035q1_driver_init); | ||
818 | |||
819 | static void __exit bfin_lq035q1_driver_cleanup(void) | ||
820 | { | ||
821 | platform_driver_unregister(&bfin_lq035q1_driver); | ||
822 | } | ||
823 | module_exit(bfin_lq035q1_driver_cleanup); | ||
824 | |||
825 | MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); | ||
826 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 5cc36cfbf07b..2549c53b26a0 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c | |||
@@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) | |||
487 | 487 | ||
488 | fbinfo->var.nonstd = 0; | 488 | fbinfo->var.nonstd = 0; |
489 | fbinfo->var.activate = FB_ACTIVATE_NOW; | 489 | fbinfo->var.activate = FB_ACTIVATE_NOW; |
490 | fbinfo->var.height = -1; | 490 | fbinfo->var.height = 53; |
491 | fbinfo->var.width = -1; | 491 | fbinfo->var.width = 70; |
492 | fbinfo->var.accel_flags = 0; | 492 | fbinfo->var.accel_flags = 0; |
493 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; | 493 | fbinfo->var.vmode = FB_VMODE_NONINTERLACED; |
494 | 494 | ||
@@ -634,17 +634,35 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) | |||
634 | #ifdef CONFIG_PM | 634 | #ifdef CONFIG_PM |
635 | static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) | 635 | static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) |
636 | { | 636 | { |
637 | bfin_t350mcqb_disable_ppi(); | 637 | struct fb_info *fbinfo = platform_get_drvdata(pdev); |
638 | disable_dma(CH_PPI); | 638 | struct bfin_t350mcqbfb_info *fbi = fbinfo->par; |
639 | bfin_write_PPI_STATUS(0xFFFF); | 639 | |
640 | if (fbi->lq043_open_cnt) { | ||
641 | bfin_t350mcqb_disable_ppi(); | ||
642 | disable_dma(CH_PPI); | ||
643 | bfin_t350mcqb_stop_timers(); | ||
644 | bfin_write_PPI_STATUS(-1); | ||
645 | } | ||
646 | |||
640 | 647 | ||
641 | return 0; | 648 | return 0; |
642 | } | 649 | } |
643 | 650 | ||
644 | static int bfin_t350mcqb_resume(struct platform_device *pdev) | 651 | static int bfin_t350mcqb_resume(struct platform_device *pdev) |
645 | { | 652 | { |
646 | enable_dma(CH_PPI); | 653 | struct fb_info *fbinfo = platform_get_drvdata(pdev); |
647 | bfin_t350mcqb_enable_ppi(); | 654 | struct bfin_t350mcqbfb_info *fbi = fbinfo->par; |
655 | |||
656 | if (fbi->lq043_open_cnt) { | ||
657 | bfin_t350mcqb_config_dma(fbi); | ||
658 | bfin_t350mcqb_config_ppi(fbi); | ||
659 | bfin_t350mcqb_init_timers(); | ||
660 | |||
661 | /* start dma */ | ||
662 | enable_dma(CH_PPI); | ||
663 | bfin_t350mcqb_enable_ppi(); | ||
664 | bfin_t350mcqb_start_timers(); | ||
665 | } | ||
648 | 666 | ||
649 | return 0; | 667 | return 0; |
650 | } | 668 | } |
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 16f5db471ab5..99b354b8e257 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -19,8 +19,10 @@ | |||
19 | * | 19 | * |
20 | * Framebuffer driver for the CLPS7111 and EP7212 processors. | 20 | * Framebuffer driver for the CLPS7111 and EP7212 processors. |
21 | */ | 21 | */ |
22 | #include <linux/mm.h> | ||
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/seq_file.h> | ||
24 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
25 | #include <linux/fb.h> | 27 | #include <linux/fb.h> |
26 | #include <linux/init.h> | 28 | #include <linux/init.h> |
@@ -38,14 +40,6 @@ struct fb_info *cfb; | |||
38 | 40 | ||
39 | #define CMAP_MAX_SIZE 16 | 41 | #define CMAP_MAX_SIZE 16 |
40 | 42 | ||
41 | /* The /proc entry for the backlight. */ | ||
42 | static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; | ||
43 | |||
44 | static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, | ||
45 | int count, int *eof, void *data); | ||
46 | static int clps7111fb_proc_backlight_write(struct file *file, | ||
47 | const char *buffer, unsigned long count, void *data); | ||
48 | |||
49 | /* | 43 | /* |
50 | * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. | 44 | * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. |
51 | * This determines how many clocks + 1 of CL1 before the M signal toggles. | 45 | * This determines how many clocks + 1 of CL1 before the M signal toggles. |
@@ -221,26 +215,23 @@ static struct fb_ops clps7111fb_ops = { | |||
221 | .fb_imageblit = cfb_imageblit, | 215 | .fb_imageblit = cfb_imageblit, |
222 | }; | 216 | }; |
223 | 217 | ||
224 | static int | 218 | static int backlight_proc_show(struct seq_file *m, void *v) |
225 | clps7111fb_proc_backlight_read(char *page, char **start, off_t off, | ||
226 | int count, int *eof, void *data) | ||
227 | { | 219 | { |
228 | /* We need at least two characters, one for the digit, and one for | ||
229 | * the terminating NULL. */ | ||
230 | if (count < 2) | ||
231 | return -EINVAL; | ||
232 | |||
233 | if (machine_is_edb7211()) { | 220 | if (machine_is_edb7211()) { |
234 | return sprintf(page, "%d\n", | 221 | seq_printf(m, "%d\n", |
235 | (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); | 222 | (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); |
236 | } | 223 | } |
237 | 224 | ||
238 | return 0; | 225 | return 0; |
239 | } | 226 | } |
240 | 227 | ||
241 | static int | 228 | static int backlight_proc_open(struct inode *inode, struct file *file) |
242 | clps7111fb_proc_backlight_write(struct file *file, const char *buffer, | 229 | { |
243 | unsigned long count, void *data) | 230 | return single_open(file, backlight_proc_show, NULL); |
231 | } | ||
232 | |||
233 | static ssize_t backlight_proc_write(struct file *file, const char *buffer, | ||
234 | size_t count, loff_t *pos) | ||
244 | { | 235 | { |
245 | unsigned char char_value; | 236 | unsigned char char_value; |
246 | int value; | 237 | int value; |
@@ -271,6 +262,15 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer, | |||
271 | return count; | 262 | return count; |
272 | } | 263 | } |
273 | 264 | ||
265 | static const struct file_operations backlight_proc_fops = { | ||
266 | .owner = THIS_MODULE, | ||
267 | .open = backlight_proc_open, | ||
268 | .read = seq_read, | ||
269 | .llseek = seq_lseek, | ||
270 | .release = single_release, | ||
271 | .write = backlight_proc_write, | ||
272 | }; | ||
273 | |||
274 | static void __init clps711x_guess_lcd_params(struct fb_info *info) | 274 | static void __init clps711x_guess_lcd_params(struct fb_info *info) |
275 | { | 275 | { |
276 | unsigned int lcdcon, syscon, size; | 276 | unsigned int lcdcon, syscon, size; |
@@ -379,19 +379,11 @@ int __init clps711xfb_init(void) | |||
379 | 379 | ||
380 | fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); | 380 | fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); |
381 | 381 | ||
382 | /* Register the /proc entries. */ | 382 | if (!proc_create("backlight", 0444, NULL, &backlight_proc_fops)) { |
383 | clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, | ||
384 | NULL); | ||
385 | if (clps7111fb_backlight_proc_entry == NULL) { | ||
386 | printk("Couldn't create the /proc entry for the backlight.\n"); | 383 | printk("Couldn't create the /proc entry for the backlight.\n"); |
387 | return -EINVAL; | 384 | return -EINVAL; |
388 | } | 385 | } |
389 | 386 | ||
390 | clps7111fb_backlight_proc_entry->read_proc = | ||
391 | &clps7111fb_proc_backlight_read; | ||
392 | clps7111fb_backlight_proc_entry->write_proc = | ||
393 | &clps7111fb_proc_backlight_write; | ||
394 | |||
395 | /* | 387 | /* |
396 | * Power up the LCD | 388 | * Power up the LCD |
397 | */ | 389 | */ |
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index ea1fd3f47511..369a5b3ac649 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/cpufreq.h> | ||
32 | #include <linux/console.h> | ||
31 | #include <video/da8xx-fb.h> | 33 | #include <video/da8xx-fb.h> |
32 | 34 | ||
33 | #define DRIVER_NAME "da8xx_lcdc" | 35 | #define DRIVER_NAME "da8xx_lcdc" |
@@ -113,6 +115,12 @@ struct da8xx_fb_par { | |||
113 | unsigned short pseudo_palette[16]; | 115 | unsigned short pseudo_palette[16]; |
114 | unsigned int databuf_sz; | 116 | unsigned int databuf_sz; |
115 | unsigned int palette_sz; | 117 | unsigned int palette_sz; |
118 | unsigned int pxl_clk; | ||
119 | int blank; | ||
120 | #ifdef CONFIG_CPU_FREQ | ||
121 | struct notifier_block freq_transition; | ||
122 | #endif | ||
123 | void (*panel_power_ctrl)(int); | ||
116 | }; | 124 | }; |
117 | 125 | ||
118 | /* Variable Screen Information */ | 126 | /* Variable Screen Information */ |
@@ -155,7 +163,7 @@ struct da8xx_panel { | |||
155 | int vfp; /* Vertical front porch */ | 163 | int vfp; /* Vertical front porch */ |
156 | int vbp; /* Vertical back porch */ | 164 | int vbp; /* Vertical back porch */ |
157 | int vsw; /* Vertical Sync Pulse Width */ | 165 | int vsw; /* Vertical Sync Pulse Width */ |
158 | int pxl_clk; /* Pixel clock */ | 166 | unsigned int pxl_clk; /* Pixel clock */ |
159 | unsigned char invert_pxl_clk; /* Invert Pixel clock */ | 167 | unsigned char invert_pxl_clk; /* Invert Pixel clock */ |
160 | }; | 168 | }; |
161 | 169 | ||
@@ -171,7 +179,7 @@ static struct da8xx_panel known_lcd_panels[] = { | |||
171 | .vfp = 2, | 179 | .vfp = 2, |
172 | .vbp = 2, | 180 | .vbp = 2, |
173 | .vsw = 0, | 181 | .vsw = 0, |
174 | .pxl_clk = 0x10, | 182 | .pxl_clk = 4608000, |
175 | .invert_pxl_clk = 1, | 183 | .invert_pxl_clk = 1, |
176 | }, | 184 | }, |
177 | /* Sharp LK043T1DG01 */ | 185 | /* Sharp LK043T1DG01 */ |
@@ -185,13 +193,23 @@ static struct da8xx_panel known_lcd_panels[] = { | |||
185 | .vfp = 2, | 193 | .vfp = 2, |
186 | .vbp = 2, | 194 | .vbp = 2, |
187 | .vsw = 10, | 195 | .vsw = 10, |
188 | .pxl_clk = 0x12, | 196 | .pxl_clk = 7833600, |
189 | .invert_pxl_clk = 0, | 197 | .invert_pxl_clk = 0, |
190 | }, | 198 | }, |
191 | }; | 199 | }; |
192 | 200 | ||
201 | /* Enable the Raster Engine of the LCD Controller */ | ||
202 | static inline void lcd_enable_raster(void) | ||
203 | { | ||
204 | u32 reg; | ||
205 | |||
206 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | ||
207 | if (!(reg & LCD_RASTER_ENABLE)) | ||
208 | lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | ||
209 | } | ||
210 | |||
193 | /* Disable the Raster Engine of the LCD Controller */ | 211 | /* Disable the Raster Engine of the LCD Controller */ |
194 | static void lcd_disable_raster(struct da8xx_fb_par *par) | 212 | static inline void lcd_disable_raster(void) |
195 | { | 213 | { |
196 | u32 reg; | 214 | u32 reg; |
197 | 215 | ||
@@ -443,14 +461,25 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
443 | static void lcd_reset(struct da8xx_fb_par *par) | 461 | static void lcd_reset(struct da8xx_fb_par *par) |
444 | { | 462 | { |
445 | /* Disable the Raster if previously Enabled */ | 463 | /* Disable the Raster if previously Enabled */ |
446 | if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) | 464 | lcd_disable_raster(); |
447 | lcd_disable_raster(par); | ||
448 | 465 | ||
449 | /* DMA has to be disabled */ | 466 | /* DMA has to be disabled */ |
450 | lcdc_write(0, LCD_DMA_CTRL_REG); | 467 | lcdc_write(0, LCD_DMA_CTRL_REG); |
451 | lcdc_write(0, LCD_RASTER_CTRL_REG); | 468 | lcdc_write(0, LCD_RASTER_CTRL_REG); |
452 | } | 469 | } |
453 | 470 | ||
471 | static void lcd_calc_clk_divider(struct da8xx_fb_par *par) | ||
472 | { | ||
473 | unsigned int lcd_clk, div; | ||
474 | |||
475 | lcd_clk = clk_get_rate(par->lcdc_clk); | ||
476 | div = lcd_clk / par->pxl_clk; | ||
477 | |||
478 | /* Configure the LCD clock divisor. */ | ||
479 | lcdc_write(LCD_CLK_DIVISOR(div) | | ||
480 | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); | ||
481 | } | ||
482 | |||
454 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | 483 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, |
455 | struct da8xx_panel *panel) | 484 | struct da8xx_panel *panel) |
456 | { | 485 | { |
@@ -459,9 +488,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
459 | 488 | ||
460 | lcd_reset(par); | 489 | lcd_reset(par); |
461 | 490 | ||
462 | /* Configure the LCD clock divisor. */ | 491 | /* Calculate the divider */ |
463 | lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | | 492 | lcd_calc_clk_divider(par); |
464 | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); | ||
465 | 493 | ||
466 | if (panel->invert_pxl_clk) | 494 | if (panel->invert_pxl_clk) |
467 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | | 495 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | |
@@ -513,13 +541,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
513 | static irqreturn_t lcdc_irq_handler(int irq, void *arg) | 541 | static irqreturn_t lcdc_irq_handler(int irq, void *arg) |
514 | { | 542 | { |
515 | u32 stat = lcdc_read(LCD_STAT_REG); | 543 | u32 stat = lcdc_read(LCD_STAT_REG); |
516 | u32 reg; | ||
517 | 544 | ||
518 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 545 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
519 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | 546 | lcd_disable_raster(); |
520 | lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | ||
521 | lcdc_write(stat, LCD_STAT_REG); | 547 | lcdc_write(stat, LCD_STAT_REG); |
522 | lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | 548 | lcd_enable_raster(); |
523 | } else | 549 | } else |
524 | lcdc_write(stat, LCD_STAT_REG); | 550 | lcdc_write(stat, LCD_STAT_REG); |
525 | 551 | ||
@@ -574,6 +600,38 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
574 | return err; | 600 | return err; |
575 | } | 601 | } |
576 | 602 | ||
603 | #ifdef CONFIG_CPU_FREQ | ||
604 | static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | ||
605 | unsigned long val, void *data) | ||
606 | { | ||
607 | struct da8xx_fb_par *par; | ||
608 | |||
609 | par = container_of(nb, struct da8xx_fb_par, freq_transition); | ||
610 | if (val == CPUFREQ_PRECHANGE) { | ||
611 | lcd_disable_raster(); | ||
612 | } else if (val == CPUFREQ_POSTCHANGE) { | ||
613 | lcd_calc_clk_divider(par); | ||
614 | lcd_enable_raster(); | ||
615 | } | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) | ||
621 | { | ||
622 | par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; | ||
623 | |||
624 | return cpufreq_register_notifier(&par->freq_transition, | ||
625 | CPUFREQ_TRANSITION_NOTIFIER); | ||
626 | } | ||
627 | |||
628 | static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) | ||
629 | { | ||
630 | cpufreq_unregister_notifier(&par->freq_transition, | ||
631 | CPUFREQ_TRANSITION_NOTIFIER); | ||
632 | } | ||
633 | #endif | ||
634 | |||
577 | static int __devexit fb_remove(struct platform_device *dev) | 635 | static int __devexit fb_remove(struct platform_device *dev) |
578 | { | 636 | { |
579 | struct fb_info *info = dev_get_drvdata(&dev->dev); | 637 | struct fb_info *info = dev_get_drvdata(&dev->dev); |
@@ -581,8 +639,13 @@ static int __devexit fb_remove(struct platform_device *dev) | |||
581 | if (info) { | 639 | if (info) { |
582 | struct da8xx_fb_par *par = info->par; | 640 | struct da8xx_fb_par *par = info->par; |
583 | 641 | ||
584 | if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) | 642 | #ifdef CONFIG_CPU_FREQ |
585 | lcd_disable_raster(par); | 643 | lcd_da8xx_cpufreq_deregister(par); |
644 | #endif | ||
645 | if (par->panel_power_ctrl) | ||
646 | par->panel_power_ctrl(0); | ||
647 | |||
648 | lcd_disable_raster(); | ||
586 | lcdc_write(0, LCD_RASTER_CTRL_REG); | 649 | lcdc_write(0, LCD_RASTER_CTRL_REG); |
587 | 650 | ||
588 | /* disable DMA */ | 651 | /* disable DMA */ |
@@ -639,6 +702,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
639 | return 0; | 702 | return 0; |
640 | } | 703 | } |
641 | 704 | ||
705 | static int cfb_blank(int blank, struct fb_info *info) | ||
706 | { | ||
707 | struct da8xx_fb_par *par = info->par; | ||
708 | int ret = 0; | ||
709 | |||
710 | if (par->blank == blank) | ||
711 | return 0; | ||
712 | |||
713 | par->blank = blank; | ||
714 | switch (blank) { | ||
715 | case FB_BLANK_UNBLANK: | ||
716 | if (par->panel_power_ctrl) | ||
717 | par->panel_power_ctrl(1); | ||
718 | |||
719 | lcd_enable_raster(); | ||
720 | break; | ||
721 | case FB_BLANK_POWERDOWN: | ||
722 | if (par->panel_power_ctrl) | ||
723 | par->panel_power_ctrl(0); | ||
724 | |||
725 | lcd_disable_raster(); | ||
726 | break; | ||
727 | default: | ||
728 | ret = -EINVAL; | ||
729 | } | ||
730 | |||
731 | return ret; | ||
732 | } | ||
733 | |||
642 | static struct fb_ops da8xx_fb_ops = { | 734 | static struct fb_ops da8xx_fb_ops = { |
643 | .owner = THIS_MODULE, | 735 | .owner = THIS_MODULE, |
644 | .fb_check_var = fb_check_var, | 736 | .fb_check_var = fb_check_var, |
@@ -647,6 +739,7 @@ static struct fb_ops da8xx_fb_ops = { | |||
647 | .fb_fillrect = cfb_fillrect, | 739 | .fb_fillrect = cfb_fillrect, |
648 | .fb_copyarea = cfb_copyarea, | 740 | .fb_copyarea = cfb_copyarea, |
649 | .fb_imageblit = cfb_imageblit, | 741 | .fb_imageblit = cfb_imageblit, |
742 | .fb_blank = cfb_blank, | ||
650 | }; | 743 | }; |
651 | 744 | ||
652 | static int __init fb_probe(struct platform_device *device) | 745 | static int __init fb_probe(struct platform_device *device) |
@@ -721,6 +814,12 @@ static int __init fb_probe(struct platform_device *device) | |||
721 | } | 814 | } |
722 | 815 | ||
723 | par = da8xx_fb_info->par; | 816 | par = da8xx_fb_info->par; |
817 | par->lcdc_clk = fb_clk; | ||
818 | par->pxl_clk = lcdc_info->pxl_clk; | ||
819 | if (fb_pdata->panel_power_ctrl) { | ||
820 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; | ||
821 | par->panel_power_ctrl(1); | ||
822 | } | ||
724 | 823 | ||
725 | if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { | 824 | if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { |
726 | dev_err(&device->dev, "lcd_init failed\n"); | 825 | dev_err(&device->dev, "lcd_init failed\n"); |
@@ -754,8 +853,6 @@ static int __init fb_probe(struct platform_device *device) | |||
754 | da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; | 853 | da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; |
755 | da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; | 854 | da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; |
756 | 855 | ||
757 | par->lcdc_clk = fb_clk; | ||
758 | |||
759 | par->irq = platform_get_irq(device, 0); | 856 | par->irq = platform_get_irq(device, 0); |
760 | if (par->irq < 0) { | 857 | if (par->irq < 0) { |
761 | ret = -ENOENT; | 858 | ret = -ENOENT; |
@@ -814,12 +911,24 @@ static int __init fb_probe(struct platform_device *device) | |||
814 | goto err_dealloc_cmap; | 911 | goto err_dealloc_cmap; |
815 | } | 912 | } |
816 | 913 | ||
914 | #ifdef CONFIG_CPU_FREQ | ||
915 | ret = lcd_da8xx_cpufreq_register(par); | ||
916 | if (ret) { | ||
917 | dev_err(&device->dev, "failed to register cpufreq\n"); | ||
918 | goto err_cpu_freq; | ||
919 | } | ||
920 | #endif | ||
921 | |||
817 | /* enable raster engine */ | 922 | /* enable raster engine */ |
818 | lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | | 923 | lcd_enable_raster(); |
819 | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | ||
820 | 924 | ||
821 | return 0; | 925 | return 0; |
822 | 926 | ||
927 | #ifdef CONFIG_CPU_FREQ | ||
928 | err_cpu_freq: | ||
929 | unregister_framebuffer(da8xx_fb_info); | ||
930 | #endif | ||
931 | |||
823 | err_dealloc_cmap: | 932 | err_dealloc_cmap: |
824 | fb_dealloc_cmap(&da8xx_fb_info->cmap); | 933 | fb_dealloc_cmap(&da8xx_fb_info->cmap); |
825 | 934 | ||
@@ -852,11 +961,35 @@ err_request_mem: | |||
852 | #ifdef CONFIG_PM | 961 | #ifdef CONFIG_PM |
853 | static int fb_suspend(struct platform_device *dev, pm_message_t state) | 962 | static int fb_suspend(struct platform_device *dev, pm_message_t state) |
854 | { | 963 | { |
855 | return -EBUSY; | 964 | struct fb_info *info = platform_get_drvdata(dev); |
965 | struct da8xx_fb_par *par = info->par; | ||
966 | |||
967 | acquire_console_sem(); | ||
968 | if (par->panel_power_ctrl) | ||
969 | par->panel_power_ctrl(0); | ||
970 | |||
971 | fb_set_suspend(info, 1); | ||
972 | lcd_disable_raster(); | ||
973 | clk_disable(par->lcdc_clk); | ||
974 | release_console_sem(); | ||
975 | |||
976 | return 0; | ||
856 | } | 977 | } |
857 | static int fb_resume(struct platform_device *dev) | 978 | static int fb_resume(struct platform_device *dev) |
858 | { | 979 | { |
859 | return -EBUSY; | 980 | struct fb_info *info = platform_get_drvdata(dev); |
981 | struct da8xx_fb_par *par = info->par; | ||
982 | |||
983 | acquire_console_sem(); | ||
984 | if (par->panel_power_ctrl) | ||
985 | par->panel_power_ctrl(1); | ||
986 | |||
987 | clk_enable(par->lcdc_clk); | ||
988 | lcd_enable_raster(); | ||
989 | fb_set_suspend(info, 0); | ||
990 | release_console_sem(); | ||
991 | |||
992 | return 0; | ||
860 | } | 993 | } |
861 | #else | 994 | #else |
862 | #define fb_suspend NULL | 995 | #define fb_suspend NULL |
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index bd9d46f95291..27aab4a06198 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c | |||
@@ -358,6 +358,8 @@ static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red, | |||
358 | 358 | ||
359 | switch (info->fix.visual) { | 359 | switch (info->fix.visual) { |
360 | case FB_VISUAL_PSEUDOCOLOR: | 360 | case FB_VISUAL_PSEUDOCOLOR: |
361 | if (regno > 255) | ||
362 | return 1; | ||
361 | rgb = ((red & 0xff00) << 8) | (green & 0xff00) | | 363 | rgb = ((red & 0xff00) << 8) | (green & 0xff00) | |
362 | ((blue & 0xff00) >> 8); | 364 | ((blue & 0xff00) >> 8); |
363 | 365 | ||
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index fc68a8b0a144..cc781c00f75d 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h | |||
@@ -1,3 +1,13 @@ | |||
1 | /* Geode LX framebuffer driver | ||
2 | * | ||
3 | * Copyright (C) 2006-2007, Advanced Micro Devices,Inc. | ||
4 | * Copyright (c) 2008 Andres Salomon <dilinger@debian.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
1 | #ifndef _LXFB_H_ | 11 | #ifndef _LXFB_H_ |
2 | #define _LXFB_H_ | 12 | #define _LXFB_H_ |
3 | 13 | ||
diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c index 27fa703a2e0a..b4b3670667ab 100644 --- a/drivers/video/i810/i810_dvt.c +++ b/drivers/video/i810/i810_dvt.c | |||
@@ -212,24 +212,29 @@ inline void round_off_yres(u32 *xres, u32 *yres) | |||
212 | *yres = (*xres * 3) >> 2; | 212 | *yres = (*xres * 3) >> 2; |
213 | } | 213 | } |
214 | 214 | ||
215 | void i810fb_encode_registers(const struct fb_var_screeninfo *var, | 215 | static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock) |
216 | struct i810fb_par *par, u32 xres, u32 yres) | ||
217 | { | 216 | { |
218 | u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; | 217 | u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; |
219 | u8 hfl; | 218 | u8 hfl = (u8) ((xres >> 3) - 1); |
220 | 219 | ||
221 | hfl = (u8) ((xres >> 3) - 1); | ||
222 | for (i = 0; i < ARRAY_SIZE(std_modes); i++) { | 220 | for (i = 0; i < ARRAY_SIZE(std_modes); i++) { |
223 | if (std_modes[i].cr01 == hfl) { | 221 | if (std_modes[i].cr01 == hfl) { |
224 | if (std_modes[i].pixclock <= par->regs.pixclock) | 222 | if (std_modes[i].pixclock <= pixclock) |
225 | diff = par->regs.pixclock - | 223 | diff = pixclock - std_modes[i].pixclock; |
226 | std_modes[i].pixclock; | ||
227 | if (diff < diff_best) { | 224 | if (diff < diff_best) { |
228 | i_best = i; | 225 | i_best = i; |
229 | diff_best = diff; | 226 | diff_best = diff; |
230 | } | 227 | } |
231 | } | 228 | } |
232 | } | 229 | } |
230 | return i_best; | ||
231 | } | ||
232 | |||
233 | void i810fb_encode_registers(const struct fb_var_screeninfo *var, | ||
234 | struct i810fb_par *par, u32 xres, u32 yres) | ||
235 | { | ||
236 | u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock); | ||
237 | |||
233 | par->regs = std_modes[i_best]; | 238 | par->regs = std_modes[i_best]; |
234 | 239 | ||
235 | /* overlay */ | 240 | /* overlay */ |
@@ -239,36 +244,36 @@ void i810fb_encode_registers(const struct fb_var_screeninfo *var, | |||
239 | 244 | ||
240 | void i810fb_fill_var_timings(struct fb_var_screeninfo *var) | 245 | void i810fb_fill_var_timings(struct fb_var_screeninfo *var) |
241 | { | 246 | { |
242 | struct i810fb_par par; | ||
243 | u32 total, xres, yres; | 247 | u32 total, xres, yres; |
248 | u32 mode, pixclock; | ||
244 | 249 | ||
245 | xres = var->xres; | 250 | xres = var->xres; |
246 | yres = var->yres; | 251 | yres = var->yres; |
247 | 252 | ||
248 | par.regs.pixclock = 1000000000/var->pixclock; | 253 | pixclock = 1000000000 / var->pixclock; |
249 | i810fb_encode_registers(var, &par, xres, yres); | 254 | mode = i810fb_find_best_mode(xres, yres, pixclock); |
250 | 255 | ||
251 | total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3; | 256 | total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3; |
257 | total <<= 3; | ||
252 | 258 | ||
253 | var->pixclock = 1000000000/par.regs.pixclock; | 259 | var->pixclock = 1000000000 / std_modes[mode].pixclock; |
254 | var->right_margin = (par.regs.cr04 << 3) - xres; | 260 | var->right_margin = (std_modes[mode].cr04 << 3) - xres; |
255 | var->hsync_len = ((par.regs.cr05 & 0x1F) - | 261 | var->hsync_len = ((std_modes[mode].cr05 & 0x1F) - |
256 | (par.regs.cr04 & 0x1F)) << 3; | 262 | (std_modes[mode].cr04 & 0x1F)) << 3; |
257 | var->left_margin = (total - (xres + var->right_margin + | 263 | var->left_margin = (total - (xres + var->right_margin + |
258 | var->hsync_len)); | 264 | var->hsync_len)); |
259 | var->sync = FB_SYNC_ON_GREEN; | 265 | var->sync = FB_SYNC_ON_GREEN; |
260 | if (~(par.regs.msr & (1 << 6))) | 266 | if (~(std_modes[mode].msr & (1 << 6))) |
261 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | 267 | var->sync |= FB_SYNC_HOR_HIGH_ACT; |
262 | if (~(par.regs.msr & (1 << 7))) | 268 | if (~(std_modes[mode].msr & (1 << 7))) |
263 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | 269 | var->sync |= FB_SYNC_VERT_HIGH_ACT; |
264 | 270 | ||
265 | 271 | total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2; | |
266 | total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F) << 8)) + 2; | 272 | var->lower_margin = (std_modes[mode].cr10 | |
267 | var->lower_margin = (par.regs.cr10 | | 273 | (std_modes[mode].cr32 & 0x0F) << 8) - yres; |
268 | (par.regs.cr32 & 0x0F) << 8) - yres; | 274 | var->vsync_len = (std_modes[mode].cr11 & 0x0F) - |
269 | var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F); | 275 | (var->lower_margin & 0x0F); |
270 | var->upper_margin = total - (yres + var->lower_margin + | 276 | var->upper_margin = total - (yres + var->lower_margin + var->vsync_len); |
271 | var->vsync_len); | ||
272 | } | 277 | } |
273 | 278 | ||
274 | u32 i810_get_watermark(struct fb_var_screeninfo *var, | 279 | u32 i810_get_watermark(struct fb_var_screeninfo *var, |
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 0cafd642fbc0..5ba399991050 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c | |||
@@ -874,6 +874,9 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, | |||
874 | if (bailearly == 18) | 874 | if (bailearly == 18) |
875 | bailout(dinfo); | 875 | bailout(dinfo); |
876 | 876 | ||
877 | /* read active pipe */ | ||
878 | dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state); | ||
879 | |||
877 | /* Cursor initialisation */ | 880 | /* Cursor initialisation */ |
878 | if (dinfo->hwcursor) { | 881 | if (dinfo->hwcursor) { |
879 | intelfbhw_cursor_init(dinfo); | 882 | intelfbhw_cursor_init(dinfo); |
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 0689f97c5238..81627466804e 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c | |||
@@ -469,6 +469,32 @@ void intelfbhw_do_blank(int blank, struct fb_info *info) | |||
469 | } | 469 | } |
470 | 470 | ||
471 | 471 | ||
472 | /* Check which pipe is connected to an active display plane. */ | ||
473 | int intelfbhw_active_pipe(const struct intelfb_hwstate *hw) | ||
474 | { | ||
475 | int pipe = -1; | ||
476 | |||
477 | /* keep old default behaviour - prefer PIPE_A */ | ||
478 | if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) { | ||
479 | pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); | ||
480 | pipe &= PIPE_MASK; | ||
481 | if (unlikely(pipe == PIPE_A)) | ||
482 | return PIPE_A; | ||
483 | } | ||
484 | if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) { | ||
485 | pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); | ||
486 | pipe &= PIPE_MASK; | ||
487 | if (likely(pipe == PIPE_A)) | ||
488 | return PIPE_A; | ||
489 | } | ||
490 | /* Impossible that no pipe is selected - return PIPE_A */ | ||
491 | WARN_ON(pipe == -1); | ||
492 | if (unlikely(pipe == -1)) | ||
493 | pipe = PIPE_A; | ||
494 | |||
495 | return pipe; | ||
496 | } | ||
497 | |||
472 | void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, | 498 | void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, |
473 | unsigned red, unsigned green, unsigned blue, | 499 | unsigned red, unsigned green, unsigned blue, |
474 | unsigned transp) | 500 | unsigned transp) |
@@ -1019,7 +1045,7 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, | |||
1019 | struct intelfb_hwstate *hw, | 1045 | struct intelfb_hwstate *hw, |
1020 | struct fb_var_screeninfo *var) | 1046 | struct fb_var_screeninfo *var) |
1021 | { | 1047 | { |
1022 | int pipe = PIPE_A; | 1048 | int pipe = intelfbhw_active_pipe(hw); |
1023 | u32 *dpll, *fp0, *fp1; | 1049 | u32 *dpll, *fp0, *fp1; |
1024 | u32 m1, m2, n, p1, p2, clock_target, clock; | 1050 | u32 m1, m2, n, p1, p2, clock_target, clock; |
1025 | u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; | 1051 | u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; |
@@ -1033,12 +1059,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, | |||
1033 | /* Disable VGA */ | 1059 | /* Disable VGA */ |
1034 | hw->vgacntrl |= VGA_DISABLE; | 1060 | hw->vgacntrl |= VGA_DISABLE; |
1035 | 1061 | ||
1036 | /* Check whether pipe A or pipe B is enabled. */ | ||
1037 | if (hw->pipe_a_conf & PIPECONF_ENABLE) | ||
1038 | pipe = PIPE_A; | ||
1039 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) | ||
1040 | pipe = PIPE_B; | ||
1041 | |||
1042 | /* Set which pipe's registers will be set. */ | 1062 | /* Set which pipe's registers will be set. */ |
1043 | if (pipe == PIPE_B) { | 1063 | if (pipe == PIPE_B) { |
1044 | dpll = &hw->dpll_b; | 1064 | dpll = &hw->dpll_b; |
@@ -1262,7 +1282,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, | |||
1262 | int intelfbhw_program_mode(struct intelfb_info *dinfo, | 1282 | int intelfbhw_program_mode(struct intelfb_info *dinfo, |
1263 | const struct intelfb_hwstate *hw, int blank) | 1283 | const struct intelfb_hwstate *hw, int blank) |
1264 | { | 1284 | { |
1265 | int pipe = PIPE_A; | ||
1266 | u32 tmp; | 1285 | u32 tmp; |
1267 | const u32 *dpll, *fp0, *fp1, *pipe_conf; | 1286 | const u32 *dpll, *fp0, *fp1, *pipe_conf; |
1268 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; | 1287 | const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; |
@@ -1272,7 +1291,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1272 | u32 src_size_reg; | 1291 | u32 src_size_reg; |
1273 | u32 count, tmp_val[3]; | 1292 | u32 count, tmp_val[3]; |
1274 | 1293 | ||
1275 | /* Assume single pipe, display plane A, analog CRT. */ | 1294 | /* Assume single pipe */ |
1276 | 1295 | ||
1277 | #if VERBOSE > 0 | 1296 | #if VERBOSE > 0 |
1278 | DBG_MSG("intelfbhw_program_mode\n"); | 1297 | DBG_MSG("intelfbhw_program_mode\n"); |
@@ -1283,15 +1302,9 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, | |||
1283 | tmp |= VGA_DISABLE; | 1302 | tmp |= VGA_DISABLE; |
1284 | OUTREG(VGACNTRL, tmp); | 1303 | OUTREG(VGACNTRL, tmp); |
1285 | 1304 | ||
1286 | /* Check whether pipe A or pipe B is enabled. */ | 1305 | dinfo->pipe = intelfbhw_active_pipe(hw); |
1287 | if (hw->pipe_a_conf & PIPECONF_ENABLE) | ||
1288 | pipe = PIPE_A; | ||
1289 | else if (hw->pipe_b_conf & PIPECONF_ENABLE) | ||
1290 | pipe = PIPE_B; | ||
1291 | |||
1292 | dinfo->pipe = pipe; | ||
1293 | 1306 | ||
1294 | if (pipe == PIPE_B) { | 1307 | if (dinfo->pipe == PIPE_B) { |
1295 | dpll = &hw->dpll_b; | 1308 | dpll = &hw->dpll_b; |
1296 | fp0 = &hw->fpb0; | 1309 | fp0 = &hw->fpb0; |
1297 | fp1 = &hw->fpb1; | 1310 | fp1 = &hw->fpb1; |
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 0b076bac321b..216ca20f259f 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h | |||
@@ -604,5 +604,6 @@ extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); | |||
604 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); | 604 | extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); |
605 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); | 605 | extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); |
606 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); | 606 | extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); |
607 | extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw); | ||
607 | 608 | ||
608 | #endif /* _INTELFBHW_H */ | 609 | #endif /* _INTELFBHW_H */ |
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c index 09f6e045d5be..c15f8a57498e 100644 --- a/drivers/video/matrox/g450_pll.c +++ b/drivers/video/matrox/g450_pll.c | |||
@@ -368,7 +368,8 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, | |||
368 | M1064_XDVICLKCTRL_C1DVICLKEN | | 368 | M1064_XDVICLKCTRL_C1DVICLKEN | |
369 | M1064_XDVICLKCTRL_DVILOOPCTL | | 369 | M1064_XDVICLKCTRL_DVILOOPCTL | |
370 | M1064_XDVICLKCTRL_P1LOOPBWDTCTL; | 370 | M1064_XDVICLKCTRL_P1LOOPBWDTCTL; |
371 | matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); | 371 | /* Setting this breaks PC systems so don't do it */ |
372 | /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */ | ||
372 | matroxfb_DAC_out(minfo, M1064_XPWRCTRL, | 373 | matroxfb_DAC_out(minfo, M1064_XPWRCTRL, |
373 | xpwrctrl); | 374 | xpwrctrl); |
374 | 375 | ||
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index 5e91c2b30af9..7854c7a37dc5 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c | |||
@@ -92,6 +92,9 @@ static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
92 | /* value to be written into the palette reg. */ | 92 | /* value to be written into the palette reg. */ |
93 | unsigned long hw_colorvalue = 0; | 93 | unsigned long hw_colorvalue = 0; |
94 | 94 | ||
95 | if (regno > 255) | ||
96 | return 1; | ||
97 | |||
95 | red >>= 8; /* The cmap fields are 16 bits */ | 98 | red >>= 8; /* The cmap fields are 16 bits */ |
96 | green >>= 8; /* wide, but the harware colormap */ | 99 | green >>= 8; /* wide, but the harware colormap */ |
97 | blue >>= 8; /* registers are only 8 bits wide */ | 100 | blue >>= 8; /* registers are only 8 bits wide */ |
diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile index 07664814bb1d..d7777714166b 100644 --- a/drivers/video/mb862xx/Makefile +++ b/drivers/video/mb862xx/Makefile | |||
@@ -2,4 +2,4 @@ | |||
2 | # Makefile for the MB862xx framebuffer driver | 2 | # Makefile for the MB862xx framebuffer driver |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o | 5 | obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o mb862xxfb_accel.o |
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index a28e3cfbbf70..fabb0c59a211 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c | |||
@@ -214,6 +214,8 @@ static int mb862xxfb_set_par(struct fb_info *fbi) | |||
214 | unsigned long reg, sc; | 214 | unsigned long reg, sc; |
215 | 215 | ||
216 | dev_dbg(par->dev, "%s\n", __func__); | 216 | dev_dbg(par->dev, "%s\n", __func__); |
217 | if (par->type == BT_CORALP) | ||
218 | mb862xxfb_init_accel(fbi, fbi->var.xres); | ||
217 | 219 | ||
218 | if (par->pre_init) | 220 | if (par->pre_init) |
219 | return 0; | 221 | return 0; |
@@ -453,6 +455,18 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev, | |||
453 | ptr += sprintf(ptr, "%08x = %08x\n", | 455 | ptr += sprintf(ptr, "%08x = %08x\n", |
454 | reg, inreg(disp, reg)); | 456 | reg, inreg(disp, reg)); |
455 | 457 | ||
458 | for (reg = 0x400; reg <= 0x410; reg += 4) | ||
459 | ptr += sprintf(ptr, "geo %08x = %08x\n", | ||
460 | reg, inreg(geo, reg)); | ||
461 | |||
462 | for (reg = 0x400; reg <= 0x410; reg += 4) | ||
463 | ptr += sprintf(ptr, "draw %08x = %08x\n", | ||
464 | reg, inreg(draw, reg)); | ||
465 | |||
466 | for (reg = 0x440; reg <= 0x450; reg += 4) | ||
467 | ptr += sprintf(ptr, "draw %08x = %08x\n", | ||
468 | reg, inreg(draw, reg)); | ||
469 | |||
456 | return ptr - buf; | 470 | return ptr - buf; |
457 | } | 471 | } |
458 | 472 | ||
diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h index c4c8f4dd2217..d7e7cb76bbf2 100644 --- a/drivers/video/mb862xx/mb862xxfb.h +++ b/drivers/video/mb862xx/mb862xxfb.h | |||
@@ -61,6 +61,8 @@ struct mb862xxfb_par { | |||
61 | u32 pseudo_palette[16]; | 61 | u32 pseudo_palette[16]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | extern void mb862xxfb_init_accel(struct fb_info *info, int xres); | ||
65 | |||
64 | #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) | 66 | #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) |
65 | #error "Select Lime GDC or CoralP/Carmine support, but not both together" | 67 | #error "Select Lime GDC or CoralP/Carmine support, but not both together" |
66 | #endif | 68 | #endif |
diff --git a/drivers/video/mb862xx/mb862xxfb_accel.c b/drivers/video/mb862xx/mb862xxfb_accel.c new file mode 100644 index 000000000000..049256052b1a --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * drivers/mb862xx/mb862xxfb_accel.c | ||
3 | * | ||
4 | * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support | ||
5 | * | ||
6 | * (C) 2007 Alexander Shishkin <virtuoso@slind.org> | ||
7 | * (C) 2009 Valentin Sitdikov <valentin.sitdikov@siemens.com> | ||
8 | * (C) 2009 Siemens AG | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/fb.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/pci.h> | ||
20 | #if defined(CONFIG_OF) | ||
21 | #include <linux/of_platform.h> | ||
22 | #endif | ||
23 | #include "mb862xxfb.h" | ||
24 | #include "mb862xx_reg.h" | ||
25 | #include "mb862xxfb_accel.h" | ||
26 | |||
27 | static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info) | ||
28 | { | ||
29 | struct mb862xxfb_par *par = info->par; | ||
30 | static u32 free; | ||
31 | |||
32 | u32 total = 0; | ||
33 | while (total < count) { | ||
34 | if (free) { | ||
35 | outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]); | ||
36 | total++; | ||
37 | free--; | ||
38 | } else { | ||
39 | free = (u32) inreg(draw, GDC_REG_FIFO_COUNT); | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void mb86290fb_copyarea(struct fb_info *info, | ||
45 | const struct fb_copyarea *area) | ||
46 | { | ||
47 | __u32 cmd[6]; | ||
48 | |||
49 | cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; | ||
50 | /* Set raster operation */ | ||
51 | cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); | ||
52 | cmd[2] = GDC_TYPE_BLTCOPYP << 24; | ||
53 | |||
54 | if (area->sx >= area->dx && area->sy >= area->dy) | ||
55 | cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16; | ||
56 | else if (area->sx >= area->dx && area->sy <= area->dy) | ||
57 | cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16; | ||
58 | else if (area->sx <= area->dx && area->sy >= area->dy) | ||
59 | cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16; | ||
60 | else | ||
61 | cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16; | ||
62 | |||
63 | cmd[3] = (area->sy << 16) | area->sx; | ||
64 | cmd[4] = (area->dy << 16) | area->dx; | ||
65 | cmd[5] = (area->height << 16) | area->width; | ||
66 | mb862xxfb_write_fifo(6, cmd, info); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image. | ||
71 | * Make sure cmd has enough room! | ||
72 | */ | ||
73 | static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy, | ||
74 | u16 width, u16 height, u32 fgcolor, | ||
75 | u32 bgcolor, const struct fb_image *image, | ||
76 | struct fb_info *info) | ||
77 | { | ||
78 | int i; | ||
79 | unsigned const char *line; | ||
80 | u16 bytes; | ||
81 | |||
82 | /* set colors and raster operation regs */ | ||
83 | cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; | ||
84 | /* Set raster operation */ | ||
85 | cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); | ||
86 | cmd[2] = | ||
87 | (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); | ||
88 | cmd[3] = fgcolor; | ||
89 | cmd[4] = | ||
90 | (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16); | ||
91 | cmd[5] = bgcolor; | ||
92 | |||
93 | i = 0; | ||
94 | line = image->data; | ||
95 | bytes = (image->width + 7) >> 3; | ||
96 | |||
97 | /* and the image */ | ||
98 | cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) | | ||
99 | (GDC_CMD_BITMAP << 16) | (2 + (step * height)); | ||
100 | cmd[7] = (dy << 16) | dx; | ||
101 | cmd[8] = (height << 16) | width; | ||
102 | |||
103 | while (i < height) { | ||
104 | memcpy(&cmd[9 + i * step], line, step << 2); | ||
105 | #ifdef __LITTLE_ENDIAN | ||
106 | { | ||
107 | int k = 0; | ||
108 | for (k = 0; k < step; k++) | ||
109 | cmd[9 + i * step + k] = | ||
110 | cpu_to_be32(cmd[9 + i * step + k]); | ||
111 | } | ||
112 | #endif | ||
113 | line += bytes; | ||
114 | i++; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image. | ||
120 | * Make sure cmd has enough room! | ||
121 | */ | ||
122 | static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy, | ||
123 | u16 width, u16 height, u32 fgcolor, | ||
124 | u32 bgcolor, const struct fb_image *image, | ||
125 | struct fb_info *info) | ||
126 | { | ||
127 | int i, j; | ||
128 | unsigned const char *line, *ptr; | ||
129 | u16 bytes; | ||
130 | |||
131 | cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | | ||
132 | (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step)); | ||
133 | cmd[1] = (dy << 16) | dx; | ||
134 | cmd[2] = (height << 16) | width; | ||
135 | |||
136 | i = 0; | ||
137 | line = ptr = image->data; | ||
138 | bytes = image->width; | ||
139 | |||
140 | while (i < height) { | ||
141 | ptr = line; | ||
142 | for (j = 0; j < step; j++) { | ||
143 | cmd[3 + i * step + j] = | ||
144 | (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff; | ||
145 | ptr++; | ||
146 | cmd[3 + i * step + j] |= | ||
147 | ((((u32 *) (info-> | ||
148 | pseudo_palette))[*ptr]) & 0xffff) << 16; | ||
149 | ptr++; | ||
150 | } | ||
151 | |||
152 | line += bytes; | ||
153 | i++; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image. | ||
159 | * Make sure cmd has enough room! | ||
160 | */ | ||
161 | static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy, | ||
162 | u16 width, u16 height, u32 fgcolor, | ||
163 | u32 bgcolor, const struct fb_image *image, | ||
164 | struct fb_info *info) | ||
165 | { | ||
166 | int i; | ||
167 | unsigned const char *line; | ||
168 | u16 bytes; | ||
169 | |||
170 | i = 0; | ||
171 | line = image->data; | ||
172 | bytes = image->width << 1; | ||
173 | |||
174 | cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | | ||
175 | (GDC_CMD_BLT_DRAW << 16) | (2 + step * height); | ||
176 | cmd[1] = (dy << 16) | dx; | ||
177 | cmd[2] = (height << 16) | width; | ||
178 | |||
179 | while (i < height) { | ||
180 | memcpy(&cmd[3 + i * step], line, step); | ||
181 | line += bytes; | ||
182 | i++; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static void mb86290fb_imageblit(struct fb_info *info, | ||
187 | const struct fb_image *image) | ||
188 | { | ||
189 | int mdr; | ||
190 | u32 *cmd = NULL; | ||
191 | void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32, | ||
192 | const struct fb_image *, struct fb_info *) = NULL; | ||
193 | u32 cmdlen; | ||
194 | u32 fgcolor = 0, bgcolor = 0; | ||
195 | u16 step; | ||
196 | |||
197 | u16 width = image->width, height = image->height; | ||
198 | u16 dx = image->dx, dy = image->dy; | ||
199 | int x2, y2, vxres, vyres; | ||
200 | |||
201 | mdr = (GDC_ROP_COPY << 9); | ||
202 | x2 = image->dx + image->width; | ||
203 | y2 = image->dy + image->height; | ||
204 | vxres = info->var.xres_virtual; | ||
205 | vyres = info->var.yres_virtual; | ||
206 | x2 = min(x2, vxres); | ||
207 | y2 = min(y2, vyres); | ||
208 | width = x2 - dx; | ||
209 | height = y2 - dy; | ||
210 | |||
211 | switch (image->depth) { | ||
212 | case 1: | ||
213 | step = (width + 31) >> 5; | ||
214 | cmdlen = 9 + height * step; | ||
215 | cmdfn = mb86290fb_imageblit1; | ||
216 | if (info->fix.visual == FB_VISUAL_TRUECOLOR || | ||
217 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
218 | fgcolor = | ||
219 | ((u32 *) (info->pseudo_palette))[image->fg_color]; | ||
220 | bgcolor = | ||
221 | ((u32 *) (info->pseudo_palette))[image->bg_color]; | ||
222 | } else { | ||
223 | fgcolor = image->fg_color; | ||
224 | bgcolor = image->bg_color; | ||
225 | } | ||
226 | |||
227 | break; | ||
228 | |||
229 | case 8: | ||
230 | step = (width + 1) >> 1; | ||
231 | cmdlen = 3 + height * step; | ||
232 | cmdfn = mb86290fb_imageblit8; | ||
233 | break; | ||
234 | |||
235 | case 16: | ||
236 | step = (width + 1) >> 1; | ||
237 | cmdlen = 3 + height * step; | ||
238 | cmdfn = mb86290fb_imageblit16; | ||
239 | break; | ||
240 | |||
241 | default: | ||
242 | cfb_imageblit(info, image); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | cmd = kmalloc(cmdlen * 4, GFP_DMA); | ||
247 | if (!cmd) | ||
248 | return cfb_imageblit(info, image); | ||
249 | cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); | ||
250 | mb862xxfb_write_fifo(cmdlen, cmd, info); | ||
251 | kfree(cmd); | ||
252 | } | ||
253 | |||
254 | static void mb86290fb_fillrect(struct fb_info *info, | ||
255 | const struct fb_fillrect *rect) | ||
256 | { | ||
257 | |||
258 | u32 x2, y2, vxres, vyres, height, width, fg; | ||
259 | u32 cmd[7]; | ||
260 | |||
261 | vxres = info->var.xres_virtual; | ||
262 | vyres = info->var.yres_virtual; | ||
263 | |||
264 | if (!rect->width || !rect->height || rect->dx > vxres | ||
265 | || rect->dy > vyres) | ||
266 | return; | ||
267 | |||
268 | /* We could use hardware clipping but on many cards you get around | ||
269 | * hardware clipping by writing to framebuffer directly. */ | ||
270 | x2 = rect->dx + rect->width; | ||
271 | y2 = rect->dy + rect->height; | ||
272 | x2 = min(x2, vxres); | ||
273 | y2 = min(y2, vyres); | ||
274 | width = x2 - rect->dx; | ||
275 | height = y2 - rect->dy; | ||
276 | if (info->fix.visual == FB_VISUAL_TRUECOLOR || | ||
277 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) | ||
278 | fg = ((u32 *) (info->pseudo_palette))[rect->color]; | ||
279 | else | ||
280 | fg = rect->color; | ||
281 | |||
282 | switch (rect->rop) { | ||
283 | |||
284 | case ROP_XOR: | ||
285 | /* Set raster operation */ | ||
286 | cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9); | ||
287 | break; | ||
288 | |||
289 | case ROP_COPY: | ||
290 | /* Set raster operation */ | ||
291 | cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); | ||
292 | break; | ||
293 | |||
294 | } | ||
295 | |||
296 | cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; | ||
297 | /* cmd[1] set earlier */ | ||
298 | cmd[2] = | ||
299 | (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); | ||
300 | cmd[3] = fg; | ||
301 | cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16); | ||
302 | cmd[5] = (rect->dy << 16) | (rect->dx); | ||
303 | cmd[6] = (height << 16) | width; | ||
304 | |||
305 | mb862xxfb_write_fifo(7, cmd, info); | ||
306 | } | ||
307 | |||
308 | void mb862xxfb_init_accel(struct fb_info *info, int xres) | ||
309 | { | ||
310 | struct mb862xxfb_par *par = info->par; | ||
311 | |||
312 | if (info->var.bits_per_pixel == 32) { | ||
313 | info->fbops->fb_fillrect = cfb_fillrect; | ||
314 | info->fbops->fb_copyarea = cfb_copyarea; | ||
315 | info->fbops->fb_imageblit = cfb_imageblit; | ||
316 | } else { | ||
317 | outreg(disp, GC_L0EM, 3); | ||
318 | info->fbops->fb_fillrect = mb86290fb_fillrect; | ||
319 | info->fbops->fb_copyarea = mb86290fb_copyarea; | ||
320 | info->fbops->fb_imageblit = mb86290fb_imageblit; | ||
321 | } | ||
322 | outreg(draw, GDC_REG_DRAW_BASE, 0); | ||
323 | outreg(draw, GDC_REG_MODE_MISC, 0x8000); | ||
324 | outreg(draw, GDC_REG_X_RESOLUTION, xres); | ||
325 | |||
326 | info->flags |= | ||
327 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | | ||
328 | FBINFO_HWACCEL_IMAGEBLIT; | ||
329 | info->fix.accel = 0xff; /*FIXME: add right define */ | ||
330 | } | ||
331 | EXPORT_SYMBOL(mb862xxfb_init_accel); | ||
diff --git a/drivers/video/mb862xx/mb862xxfb_accel.h b/drivers/video/mb862xx/mb862xxfb_accel.h new file mode 100644 index 000000000000..96a2dfef0f60 --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.h | |||
@@ -0,0 +1,203 @@ | |||
1 | #ifndef __MB826XXFB_ACCEL_H__ | ||
2 | #define __MB826XXFB_ACCEL_H__ | ||
3 | |||
4 | /* registers */ | ||
5 | #define GDC_GEO_REG_INPUT_FIFO 0x00000400L | ||
6 | |||
7 | /* Special Registers */ | ||
8 | #define GDC_REG_CTRL 0x00000400L | ||
9 | #define GDC_REG_FIFO_STATUS 0x00000404L | ||
10 | #define GDC_REG_FIFO_COUNT 0x00000408L | ||
11 | #define GDC_REG_SETUP_STATUS 0x0000040CL | ||
12 | #define GDC_REG_DDA_STATUS 0x00000410L | ||
13 | #define GDC_REG_ENGINE_STATUS 0x00000414L | ||
14 | #define GDC_REG_ERROR_STATUS 0x00000418L | ||
15 | #define GDC_REG_MODE_MISC 0x00000420L /* MDR0 */ | ||
16 | #define GDC_REG_MODE_LINE 0x00000424L /* MDR1 */ | ||
17 | #define GDC_REG_MODE_POLYGON 0x00000428L /* MDR2 */ | ||
18 | #define GDC_REG_MODE_TEXTURE 0x0000042CL /* MDR3 */ | ||
19 | #define GDC_REG_MODE_BITMAP 0x00000430L /* MDR4 */ | ||
20 | #define GDC_REG_MODE_EXTENSION 0x0000043CL /* MDR7 */ | ||
21 | |||
22 | /* Configuration Registers */ | ||
23 | #define GDC_REG_DRAW_BASE 0x00000440L | ||
24 | #define GDC_REG_X_RESOLUTION 0x00000444L | ||
25 | #define GDC_REG_Z_BASE 0x00000448L | ||
26 | #define GDC_REG_TEXTURE_BASE 0x0000044CL | ||
27 | #define GDC_REG_POLYGON_FLAG_BASE 0x00000450L | ||
28 | #define GDC_REG_CLIP_XMIN 0x00000454L | ||
29 | #define GDC_REG_CLIP_XMAX 0x00000458L | ||
30 | #define GDC_REG_CLIP_YMIN 0x0000045CL | ||
31 | #define GDC_REG_CLIP_YMAX 0x00000460L | ||
32 | #define GDC_REG_TEXURE_SIZE 0x00000464L | ||
33 | #define GDC_REG_TILE_SIZE 0x00000468L | ||
34 | #define GDC_REG_TEX_BUF_OFFSET 0x0000046CL | ||
35 | |||
36 | /* for MB86293 or later */ | ||
37 | #define GDC_REG_ALPHA_MAP_BASE 0x00000474L /* ABR */ | ||
38 | |||
39 | /* Constant Registers */ | ||
40 | #define GDC_REG_FOREGROUND_COLOR 0x00000480L | ||
41 | #define GDC_REG_BACKGROUND_COLOR 0x00000484L | ||
42 | #define GDC_REG_ALPHA 0x00000488L | ||
43 | #define GDC_REG_LINE_PATTERN 0x0000048CL | ||
44 | #define GDC_REG_TEX_BORDER_COLOR 0x00000494L | ||
45 | #define GDC_REG_LINE_PATTERN_OFFSET 0x000003E0L | ||
46 | |||
47 | /* Coomand Code */ | ||
48 | #define GDC_CMD_PIXEL 0x00000000L | ||
49 | #define GDC_CMD_PIXEL_Z 0x00000001L | ||
50 | |||
51 | #define GDC_CMD_X_VECTOR 0x00000020L | ||
52 | #define GDC_CMD_Y_VECTOR 0x00000021L | ||
53 | #define GDC_CMD_X_VECTOR_NOEND 0x00000022L | ||
54 | #define GDC_CMD_Y_VECTOR_NOEND 0x00000023L | ||
55 | #define GDC_CMD_X_VECTOR_BLPO 0x00000024L | ||
56 | #define GDC_CMD_Y_VECTOR_BLPO 0x00000025L | ||
57 | #define GDC_CMD_X_VECTOR_NOEND_BLPO 0x00000026L | ||
58 | #define GDC_CMD_Y_VECTOR_NOEND_BLPO 0x00000027L | ||
59 | #define GDC_CMD_AA_X_VECTOR 0x00000028L | ||
60 | #define GDC_CMD_AA_Y_VECTOR 0x00000029L | ||
61 | #define GDC_CMD_AA_X_VECTOR_NOEND 0x0000002AL | ||
62 | #define GDC_CMD_AA_Y_VECTOR_NOEND 0x0000002BL | ||
63 | #define GDC_CMD_AA_X_VECTOR_BLPO 0x0000002CL | ||
64 | #define GDC_CMD_AA_Y_VECTOR_BLPO 0x0000002DL | ||
65 | #define GDC_CMD_AA_X_VECTOR_NOEND_BLPO 0x0000002EL | ||
66 | #define GDC_CMD_AA_Y_VECTOR_NOEND_BLPO 0x0000002FL | ||
67 | |||
68 | #define GDC_CMD_0_VECTOR 0x00000030L | ||
69 | #define GDC_CMD_1_VECTOR 0x00000031L | ||
70 | #define GDC_CMD_0_VECTOR_NOEND 0x00000032L | ||
71 | #define GDC_CMD_1_VECTOR_NOEND 0x00000033L | ||
72 | #define GDC_CMD_0_VECTOR_BLPO 0x00000034L | ||
73 | #define GDC_CMD_1_VECTOR_BLPO 0x00000035L | ||
74 | #define GDC_CMD_0_VECTOR_NOEND_BLPO 0x00000036L | ||
75 | #define GDC_CMD_1_VECTOR_NOEND_BLPO 0x00000037L | ||
76 | #define GDC_CMD_AA_0_VECTOR 0x00000038L | ||
77 | #define GDC_CMD_AA_1_VECTOR 0x00000039L | ||
78 | #define GDC_CMD_AA_0_VECTOR_NOEND 0x0000003AL | ||
79 | #define GDC_CMD_AA_1_VECTOR_NOEND 0x0000003BL | ||
80 | #define GDC_CMD_AA_0_VECTOR_BLPO 0x0000003CL | ||
81 | #define GDC_CMD_AA_1_VECTOR_BLPO 0x0000003DL | ||
82 | #define GDC_CMD_AA_0_VECTOR_NOEND_BLPO 0x0000003EL | ||
83 | #define GDC_CMD_AA_1_VECTOR_NOEND_BLPO 0x0000003FL | ||
84 | |||
85 | #define GDC_CMD_BLT_FILL 0x00000041L | ||
86 | #define GDC_CMD_BLT_DRAW 0x00000042L | ||
87 | #define GDC_CMD_BITMAP 0x00000043L | ||
88 | #define GDC_CMD_BLTCOPY_TOP_LEFT 0x00000044L | ||
89 | #define GDC_CMD_BLTCOPY_TOP_RIGHT 0x00000045L | ||
90 | #define GDC_CMD_BLTCOPY_BOTTOM_LEFT 0x00000046L | ||
91 | #define GDC_CMD_BLTCOPY_BOTTOM_RIGHT 0x00000047L | ||
92 | #define GDC_CMD_LOAD_TEXTURE 0x00000048L | ||
93 | #define GDC_CMD_LOAD_TILE 0x00000049L | ||
94 | |||
95 | #define GDC_CMD_TRAP_RIGHT 0x00000060L | ||
96 | #define GDC_CMD_TRAP_LEFT 0x00000061L | ||
97 | #define GDC_CMD_TRIANGLE_FAN 0x00000062L | ||
98 | #define GDC_CMD_FLAG_TRIANGLE_FAN 0x00000063L | ||
99 | |||
100 | #define GDC_CMD_FLUSH_FB 0x000000C1L | ||
101 | #define GDC_CMD_FLUSH_Z 0x000000C2L | ||
102 | |||
103 | #define GDC_CMD_POLYGON_BEGIN 0x000000E0L | ||
104 | #define GDC_CMD_POLYGON_END 0x000000E1L | ||
105 | #define GDC_CMD_CLEAR_POLY_FLAG 0x000000E2L | ||
106 | #define GDC_CMD_NORMAL 0x000000FFL | ||
107 | |||
108 | #define GDC_CMD_VECTOR_BLPO_FLAG 0x00040000L | ||
109 | #define GDC_CMD_FAST_VECTOR_BLPO_FLAG 0x00000004L | ||
110 | |||
111 | /* for MB86293 or later */ | ||
112 | #define GDC_CMD_MDR1 0x00000000L | ||
113 | #define GDC_CMD_MDR1S 0x00000002L | ||
114 | #define GDC_CMD_MDR1B 0x00000004L | ||
115 | #define GDC_CMD_MDR2 0x00000001L | ||
116 | #define GDC_CMD_MDR2S 0x00000003L | ||
117 | #define GDC_CMD_MDR2TL 0x00000007L | ||
118 | #define GDC_CMD_GMDR1E 0x00000010L | ||
119 | #define GDC_CMD_GMDR2E 0x00000020L | ||
120 | #define GDC_CMD_OVERLAP_SHADOW_XY 0x00000000L | ||
121 | #define GDC_CMD_OVERLAP_SHADOW_XY_COMPOSITION 0x00000001L | ||
122 | #define GDC_CMD_OVERLAP_Z_PACKED_ONBS 0x00000007L | ||
123 | #define GDC_CMD_OVERLAP_Z_ORIGIN 0x00000000L | ||
124 | #define GDC_CMD_OVERLAP_Z_NON_TOPLEFT 0x00000001L | ||
125 | #define GDC_CMD_OVERLAP_Z_BORDER 0x00000002L | ||
126 | #define GDC_CMD_OVERLAP_Z_SHADOW 0x00000003L | ||
127 | #define GDC_CMD_BLTCOPY_ALT_ALPHA 0x00000000L /* Reserverd */ | ||
128 | #define GDC_CMD_DC_LOGOUT 0x00000000L /* Reserverd */ | ||
129 | #define GDC_CMD_BODY_FORE_COLOR 0x00000000L | ||
130 | #define GDC_CMD_BODY_BACK_COLOR 0x00000001L | ||
131 | #define GDC_CMD_SHADOW_FORE_COLOR 0x00000002L | ||
132 | #define GDC_CMD_SHADOW_BACK_COLOR 0x00000003L | ||
133 | #define GDC_CMD_BORDER_FORE_COLOR 0x00000004L | ||
134 | #define GDC_CMD_BORDER_BACK_COLOR 0x00000005L | ||
135 | |||
136 | /* Type Code Table */ | ||
137 | #define GDC_TYPE_G_NOP 0x00000020L | ||
138 | #define GDC_TYPE_G_BEGIN 0x00000021L | ||
139 | #define GDC_TYPE_G_BEGINCONT 0x00000022L | ||
140 | #define GDC_TYPE_G_END 0x00000023L | ||
141 | #define GDC_TYPE_G_VERTEX 0x00000030L | ||
142 | #define GDC_TYPE_G_VERTEXLOG 0x00000032L | ||
143 | #define GDC_TYPE_G_VERTEXNOPLOG 0x00000033L | ||
144 | #define GDC_TYPE_G_INIT 0x00000040L | ||
145 | #define GDC_TYPE_G_VIEWPORT 0x00000041L | ||
146 | #define GDC_TYPE_G_DEPTHRANGE 0x00000042L | ||
147 | #define GDC_TYPE_G_LOADMATRIX 0x00000043L | ||
148 | #define GDC_TYPE_G_VIEWVOLUMEXYCLIP 0x00000044L | ||
149 | #define GDC_TYPE_G_VIEWVOLUMEZCLIP 0x00000045L | ||
150 | #define GDC_TYPE_G_VIEWVOLUMEWCLIP 0x00000046L | ||
151 | #define GDC_TYPE_SETLVERTEX2I 0x00000072L | ||
152 | #define GDC_TYPE_SETLVERTEX2IP 0x00000073L | ||
153 | #define GDC_TYPE_SETMODEREGISTER 0x000000C0L | ||
154 | #define GDC_TYPE_SETGMODEREGISTER 0x000000C1L | ||
155 | #define GDC_TYPE_OVERLAPXYOFFT 0x000000C8L | ||
156 | #define GDC_TYPE_OVERLAPZOFFT 0x000000C9L | ||
157 | #define GDC_TYPE_DC_LOGOUTADDR 0x000000CCL | ||
158 | #define GDC_TYPE_SETCOLORREGISTER 0x000000CEL | ||
159 | #define GDC_TYPE_G_BEGINE 0x000000E1L | ||
160 | #define GDC_TYPE_G_BEGINCONTE 0x000000E2L | ||
161 | #define GDC_TYPE_G_ENDE 0x000000E3L | ||
162 | #define GDC_TYPE_DRAWPIXEL 0x00000000L | ||
163 | #define GDC_TYPE_DRAWPIXELZ 0x00000001L | ||
164 | #define GDC_TYPE_DRAWLINE 0x00000002L | ||
165 | #define GDC_TYPE_DRAWLINE2I 0x00000003L | ||
166 | #define GDC_TYPE_DRAWLINE2IP 0x00000004L | ||
167 | #define GDC_TYPE_DRAWTRAP 0x00000005L | ||
168 | #define GDC_TYPE_DRAWVERTEX2I 0x00000006L | ||
169 | #define GDC_TYPE_DRAWVERTEX2IP 0x00000007L | ||
170 | #define GDC_TYPE_DRAWRECTP 0x00000009L | ||
171 | #define GDC_TYPE_DRAWBITMAPP 0x0000000BL | ||
172 | #define GDC_TYPE_BLTCOPYP 0x0000000DL | ||
173 | #define GDC_TYPE_BLTCOPYALTERNATEP 0x0000000FL | ||
174 | #define GDC_TYPE_LOADTEXTUREP 0x00000011L | ||
175 | #define GDC_TYPE_BLTTEXTUREP 0x00000013L | ||
176 | #define GDC_TYPE_BLTCOPYALTALPHABLENDP 0x0000001FL | ||
177 | #define GDC_TYPE_SETVERTEX2I 0x00000070L | ||
178 | #define GDC_TYPE_SETVERTEX2IP 0x00000071L | ||
179 | #define GDC_TYPE_DRAW 0x000000F0L | ||
180 | #define GDC_TYPE_SETREGISTER 0x000000F1L | ||
181 | #define GDC_TYPE_SYNC 0x000000FCL | ||
182 | #define GDC_TYPE_INTERRUPT 0x000000FDL | ||
183 | #define GDC_TYPE_NOP 0x0 | ||
184 | |||
185 | /* Raster operation */ | ||
186 | #define GDC_ROP_CLEAR 0x0000 | ||
187 | #define GDC_ROP_AND 0x0001 | ||
188 | #define GDC_ROP_AND_REVERSE 0x0002 | ||
189 | #define GDC_ROP_COPY 0x0003 | ||
190 | #define GDC_ROP_AND_INVERTED 0x0004 | ||
191 | #define GDC_ROP_NOP 0x0005 | ||
192 | #define GDC_ROP_XOR 0x0006 | ||
193 | #define GDC_ROP_OR 0x0007 | ||
194 | #define GDC_ROP_NOR 0x0008 | ||
195 | #define GDC_ROP_EQUIV 0x0009 | ||
196 | #define GDC_ROP_INVERT 0x000A | ||
197 | #define GDC_ROP_OR_REVERSE 0x000B | ||
198 | #define GDC_ROP_COPY_INVERTED 0x000C | ||
199 | #define GDC_ROP_OR_INVERTED 0x000D | ||
200 | #define GDC_ROP_NAND 0x000E | ||
201 | #define GDC_ROP_SET 0x000F | ||
202 | |||
203 | #endif | ||
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e7995169..0129f1bc3522 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/fb.h> | 15 | #include <linux/fb.h> |
16 | #include <linux/kernel.h> | ||
16 | 17 | ||
17 | #undef DEBUG | 18 | #undef DEBUG |
18 | 19 | ||
@@ -402,21 +403,6 @@ const struct fb_videomode vesa_modes[] = { | |||
402 | EXPORT_SYMBOL(vesa_modes); | 403 | EXPORT_SYMBOL(vesa_modes); |
403 | #endif /* CONFIG_FB_MODE_HELPERS */ | 404 | #endif /* CONFIG_FB_MODE_HELPERS */ |
404 | 405 | ||
405 | static int my_atoi(const char *name) | ||
406 | { | ||
407 | int val = 0; | ||
408 | |||
409 | for (;; name++) { | ||
410 | switch (*name) { | ||
411 | case '0' ... '9': | ||
412 | val = 10*val+(*name-'0'); | ||
413 | break; | ||
414 | default: | ||
415 | return val; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /** | 406 | /** |
421 | * fb_try_mode - test a video mode | 407 | * fb_try_mode - test a video mode |
422 | * @var: frame buffer user defined part of display | 408 | * @var: frame buffer user defined part of display |
@@ -539,7 +525,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
539 | namelen = i; | 525 | namelen = i; |
540 | if (!refresh_specified && !bpp_specified && | 526 | if (!refresh_specified && !bpp_specified && |
541 | !yres_specified) { | 527 | !yres_specified) { |
542 | refresh = my_atoi(&name[i+1]); | 528 | refresh = simple_strtol(&name[i+1], NULL, 10); |
543 | refresh_specified = 1; | 529 | refresh_specified = 1; |
544 | if (cvt || rb) | 530 | if (cvt || rb) |
545 | cvt = 0; | 531 | cvt = 0; |
@@ -549,7 +535,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
549 | case '-': | 535 | case '-': |
550 | namelen = i; | 536 | namelen = i; |
551 | if (!bpp_specified && !yres_specified) { | 537 | if (!bpp_specified && !yres_specified) { |
552 | bpp = my_atoi(&name[i+1]); | 538 | bpp = simple_strtol(&name[i+1], NULL, 10); |
553 | bpp_specified = 1; | 539 | bpp_specified = 1; |
554 | if (cvt || rb) | 540 | if (cvt || rb) |
555 | cvt = 0; | 541 | cvt = 0; |
@@ -558,7 +544,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
558 | break; | 544 | break; |
559 | case 'x': | 545 | case 'x': |
560 | if (!yres_specified) { | 546 | if (!yres_specified) { |
561 | yres = my_atoi(&name[i+1]); | 547 | yres = simple_strtol(&name[i+1], NULL, 10); |
562 | yres_specified = 1; | 548 | yres_specified = 1; |
563 | } else | 549 | } else |
564 | goto done; | 550 | goto done; |
@@ -586,7 +572,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
586 | } | 572 | } |
587 | } | 573 | } |
588 | if (i < 0 && yres_specified) { | 574 | if (i < 0 && yres_specified) { |
589 | xres = my_atoi(name); | 575 | xres = simple_strtol(name, NULL, 10); |
590 | res_specified = 1; | 576 | res_specified = 1; |
591 | } | 577 | } |
592 | done: | 578 | done: |
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0573ec685a57..0f361b6100d2 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c | |||
@@ -98,7 +98,8 @@ static int pmagbafb_setcolreg(unsigned int regno, unsigned int red, | |||
98 | { | 98 | { |
99 | struct pmagbafb_par *par = info->par; | 99 | struct pmagbafb_par *par = info->par; |
100 | 100 | ||
101 | BUG_ON(regno >= info->cmap.len); | 101 | if (regno >= info->cmap.len) |
102 | return 1; | ||
102 | 103 | ||
103 | red >>= 8; /* The cmap fields are 16 bits */ | 104 | red >>= 8; /* The cmap fields are 16 bits */ |
104 | green >>= 8; /* wide, but the hardware colormap */ | 105 | green >>= 8; /* wide, but the hardware colormap */ |
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 98748723af9f..2de0806421b4 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c | |||
@@ -102,7 +102,8 @@ static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red, | |||
102 | { | 102 | { |
103 | struct pmagbbfb_par *par = info->par; | 103 | struct pmagbbfb_par *par = info->par; |
104 | 104 | ||
105 | BUG_ON(regno >= info->cmap.len); | 105 | if (regno >= info->cmap.len) |
106 | return 1; | ||
106 | 107 | ||
107 | red >>= 8; /* The cmap fields are 16 bits */ | 108 | red >>= 8; /* The cmap fields are 16 bits */ |
108 | green >>= 8; /* wide, but the hardware colormap */ | 109 | green >>= 8; /* wide, but the hardware colormap */ |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index b7e58059b592..415858b421b3 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -1221,13 +1221,14 @@ static void setup_smart_timing(struct pxafb_info *fbi, | |||
1221 | static int pxafb_smart_thread(void *arg) | 1221 | static int pxafb_smart_thread(void *arg) |
1222 | { | 1222 | { |
1223 | struct pxafb_info *fbi = arg; | 1223 | struct pxafb_info *fbi = arg; |
1224 | struct pxafb_mach_info *inf = fbi->dev->platform_data; | 1224 | struct pxafb_mach_info *inf; |
1225 | 1225 | ||
1226 | if (!fbi || !inf->smart_update) { | 1226 | if (!fbi || !fbi->dev->platform_data->smart_update) { |
1227 | pr_err("%s: not properly initialized, thread terminated\n", | 1227 | pr_err("%s: not properly initialized, thread terminated\n", |
1228 | __func__); | 1228 | __func__); |
1229 | return -EINVAL; | 1229 | return -EINVAL; |
1230 | } | 1230 | } |
1231 | inf = fbi->dev->platform_data; | ||
1231 | 1232 | ||
1232 | pr_debug("%s(): task starting\n", __func__); | 1233 | pr_debug("%s(): task starting\n", __func__); |
1233 | 1234 | ||
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a4e05e4d7501..9d2b6bc49036 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -2115,7 +2115,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo) | |||
2115 | if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && | 2115 | if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && |
2116 | (!((ivideo->sisvga_engine == SIS_315_VGA) && | 2116 | (!((ivideo->sisvga_engine == SIS_315_VGA) && |
2117 | (ivideo->vbflags2 & VB2_CHRONTEL))) ) { | 2117 | (ivideo->vbflags2 & VB2_CHRONTEL))) ) { |
2118 | if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { | 2118 | if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) { |
2119 | ivideo->sisfb_tvstd = -1; | 2119 | ivideo->sisfb_tvstd = -1; |
2120 | printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); | 2120 | printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); |
2121 | } | 2121 | } |
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 924d79462780..35370d0ecf03 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c | |||
@@ -29,8 +29,8 @@ | |||
29 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/console.h> | 31 | #include <linux/console.h> |
32 | #include <linux/io.h> | ||
32 | 33 | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | #include <asm/div64.h> | 35 | #include <asm/div64.h> |
36 | 36 | ||
@@ -66,6 +66,7 @@ struct sm501fb_info { | |||
66 | struct fb_info *fb[2]; /* fb info for both heads */ | 66 | struct fb_info *fb[2]; /* fb info for both heads */ |
67 | struct resource *fbmem_res; /* framebuffer resource */ | 67 | struct resource *fbmem_res; /* framebuffer resource */ |
68 | struct resource *regs_res; /* registers resource */ | 68 | struct resource *regs_res; /* registers resource */ |
69 | struct resource *regs2d_res; /* 2d registers resource */ | ||
69 | struct sm501_platdata_fb *pdata; /* our platform data */ | 70 | struct sm501_platdata_fb *pdata; /* our platform data */ |
70 | 71 | ||
71 | unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ | 72 | unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ |
@@ -73,6 +74,7 @@ struct sm501fb_info { | |||
73 | int irq; | 74 | int irq; |
74 | int swap_endian; /* set to swap rgb=>bgr */ | 75 | int swap_endian; /* set to swap rgb=>bgr */ |
75 | void __iomem *regs; /* remapped registers */ | 76 | void __iomem *regs; /* remapped registers */ |
77 | void __iomem *regs2d; /* 2d remapped registers */ | ||
76 | void __iomem *fbmem; /* remapped framebuffer */ | 78 | void __iomem *fbmem; /* remapped framebuffer */ |
77 | size_t fbmem_len; /* length of remapped region */ | 79 | size_t fbmem_len; /* length of remapped region */ |
78 | }; | 80 | }; |
@@ -123,9 +125,9 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) | |||
123 | * This is an attempt to lay out memory for the two framebuffers and | 125 | * This is an attempt to lay out memory for the two framebuffers and |
124 | * everything else | 126 | * everything else |
125 | * | 127 | * |
126 | * |fbmem_res->start fbmem_res->end| | 128 | * |fbmem_res->start fbmem_res->end| |
127 | * | | | 129 | * | | |
128 | * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | | 130 | * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | |
129 | * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| | 131 | * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| |
130 | * | 132 | * |
131 | * The "spare" space is for the 2d engine data | 133 | * The "spare" space is for the 2d engine data |
@@ -1246,7 +1248,173 @@ static ssize_t sm501fb_debug_show_pnl(struct device *dev, | |||
1246 | 1248 | ||
1247 | static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); | 1249 | static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); |
1248 | 1250 | ||
1249 | /* framebuffer ops */ | 1251 | /* acceleration operations */ |
1252 | static int sm501fb_sync(struct fb_info *info) | ||
1253 | { | ||
1254 | int count = 1000000; | ||
1255 | struct sm501fb_par *par = info->par; | ||
1256 | struct sm501fb_info *fbi = par->info; | ||
1257 | |||
1258 | /* wait for the 2d engine to be ready */ | ||
1259 | while ((count > 0) && | ||
1260 | (readl(fbi->regs + SM501_SYSTEM_CONTROL) & | ||
1261 | SM501_SYSCTRL_2D_ENGINE_STATUS) != 0) | ||
1262 | count--; | ||
1263 | |||
1264 | if (count <= 0) { | ||
1265 | dev_err(info->dev, "Timeout waiting for 2d engine sync\n"); | ||
1266 | return 1; | ||
1267 | } | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | ||
1272 | { | ||
1273 | struct sm501fb_par *par = info->par; | ||
1274 | struct sm501fb_info *fbi = par->info; | ||
1275 | int width = area->width; | ||
1276 | int height = area->height; | ||
1277 | int sx = area->sx; | ||
1278 | int sy = area->sy; | ||
1279 | int dx = area->dx; | ||
1280 | int dy = area->dy; | ||
1281 | unsigned long rtl = 0; | ||
1282 | |||
1283 | /* source clip */ | ||
1284 | if ((sx >= info->var.xres_virtual) || | ||
1285 | (sy >= info->var.yres_virtual)) | ||
1286 | /* source Area not within virtual screen, skipping */ | ||
1287 | return; | ||
1288 | if ((sx + width) >= info->var.xres_virtual) | ||
1289 | width = info->var.xres_virtual - sx - 1; | ||
1290 | if ((sy + height) >= info->var.yres_virtual) | ||
1291 | height = info->var.yres_virtual - sy - 1; | ||
1292 | |||
1293 | /* dest clip */ | ||
1294 | if ((dx >= info->var.xres_virtual) || | ||
1295 | (dy >= info->var.yres_virtual)) | ||
1296 | /* Destination Area not within virtual screen, skipping */ | ||
1297 | return; | ||
1298 | if ((dx + width) >= info->var.xres_virtual) | ||
1299 | width = info->var.xres_virtual - dx - 1; | ||
1300 | if ((dy + height) >= info->var.yres_virtual) | ||
1301 | height = info->var.yres_virtual - dy - 1; | ||
1302 | |||
1303 | if ((sx < dx) || (sy < dy)) { | ||
1304 | rtl = 1 << 27; | ||
1305 | sx += width - 1; | ||
1306 | dx += width - 1; | ||
1307 | sy += height - 1; | ||
1308 | dy += height - 1; | ||
1309 | } | ||
1310 | |||
1311 | if (sm501fb_sync(info)) | ||
1312 | return; | ||
1313 | |||
1314 | /* set the base addresses */ | ||
1315 | writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); | ||
1316 | writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); | ||
1317 | |||
1318 | /* set the window width */ | ||
1319 | writel((info->var.xres << 16) | info->var.xres, | ||
1320 | fbi->regs2d + SM501_2D_WINDOW_WIDTH); | ||
1321 | |||
1322 | /* set window stride */ | ||
1323 | writel((info->var.xres_virtual << 16) | info->var.xres_virtual, | ||
1324 | fbi->regs2d + SM501_2D_PITCH); | ||
1325 | |||
1326 | /* set data format */ | ||
1327 | switch (info->var.bits_per_pixel) { | ||
1328 | case 8: | ||
1329 | writel(0, fbi->regs2d + SM501_2D_STRETCH); | ||
1330 | break; | ||
1331 | case 16: | ||
1332 | writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); | ||
1333 | break; | ||
1334 | case 32: | ||
1335 | writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); | ||
1336 | break; | ||
1337 | } | ||
1338 | |||
1339 | /* 2d compare mask */ | ||
1340 | writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); | ||
1341 | |||
1342 | /* 2d mask */ | ||
1343 | writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); | ||
1344 | |||
1345 | /* source and destination x y */ | ||
1346 | writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); | ||
1347 | writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); | ||
1348 | |||
1349 | /* w/h */ | ||
1350 | writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); | ||
1351 | |||
1352 | /* do area move */ | ||
1353 | writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); | ||
1354 | } | ||
1355 | |||
1356 | static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
1357 | { | ||
1358 | struct sm501fb_par *par = info->par; | ||
1359 | struct sm501fb_info *fbi = par->info; | ||
1360 | int width = rect->width, height = rect->height; | ||
1361 | |||
1362 | if ((rect->dx >= info->var.xres_virtual) || | ||
1363 | (rect->dy >= info->var.yres_virtual)) | ||
1364 | /* Rectangle not within virtual screen, skipping */ | ||
1365 | return; | ||
1366 | if ((rect->dx + width) >= info->var.xres_virtual) | ||
1367 | width = info->var.xres_virtual - rect->dx - 1; | ||
1368 | if ((rect->dy + height) >= info->var.yres_virtual) | ||
1369 | height = info->var.yres_virtual - rect->dy - 1; | ||
1370 | |||
1371 | if (sm501fb_sync(info)) | ||
1372 | return; | ||
1373 | |||
1374 | /* set the base addresses */ | ||
1375 | writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); | ||
1376 | writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); | ||
1377 | |||
1378 | /* set the window width */ | ||
1379 | writel((info->var.xres << 16) | info->var.xres, | ||
1380 | fbi->regs2d + SM501_2D_WINDOW_WIDTH); | ||
1381 | |||
1382 | /* set window stride */ | ||
1383 | writel((info->var.xres_virtual << 16) | info->var.xres_virtual, | ||
1384 | fbi->regs2d + SM501_2D_PITCH); | ||
1385 | |||
1386 | /* set data format */ | ||
1387 | switch (info->var.bits_per_pixel) { | ||
1388 | case 8: | ||
1389 | writel(0, fbi->regs2d + SM501_2D_STRETCH); | ||
1390 | break; | ||
1391 | case 16: | ||
1392 | writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); | ||
1393 | break; | ||
1394 | case 32: | ||
1395 | writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); | ||
1396 | break; | ||
1397 | } | ||
1398 | |||
1399 | /* 2d compare mask */ | ||
1400 | writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); | ||
1401 | |||
1402 | /* 2d mask */ | ||
1403 | writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); | ||
1404 | |||
1405 | /* colour */ | ||
1406 | writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); | ||
1407 | |||
1408 | /* x y */ | ||
1409 | writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION); | ||
1410 | |||
1411 | /* w/h */ | ||
1412 | writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); | ||
1413 | |||
1414 | /* do rectangle fill */ | ||
1415 | writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); | ||
1416 | } | ||
1417 | |||
1250 | 1418 | ||
1251 | static struct fb_ops sm501fb_ops_crt = { | 1419 | static struct fb_ops sm501fb_ops_crt = { |
1252 | .owner = THIS_MODULE, | 1420 | .owner = THIS_MODULE, |
@@ -1256,9 +1424,10 @@ static struct fb_ops sm501fb_ops_crt = { | |||
1256 | .fb_setcolreg = sm501fb_setcolreg, | 1424 | .fb_setcolreg = sm501fb_setcolreg, |
1257 | .fb_pan_display = sm501fb_pan_crt, | 1425 | .fb_pan_display = sm501fb_pan_crt, |
1258 | .fb_cursor = sm501fb_cursor, | 1426 | .fb_cursor = sm501fb_cursor, |
1259 | .fb_fillrect = cfb_fillrect, | 1427 | .fb_fillrect = sm501fb_fillrect, |
1260 | .fb_copyarea = cfb_copyarea, | 1428 | .fb_copyarea = sm501fb_copyarea, |
1261 | .fb_imageblit = cfb_imageblit, | 1429 | .fb_imageblit = cfb_imageblit, |
1430 | .fb_sync = sm501fb_sync, | ||
1262 | }; | 1431 | }; |
1263 | 1432 | ||
1264 | static struct fb_ops sm501fb_ops_pnl = { | 1433 | static struct fb_ops sm501fb_ops_pnl = { |
@@ -1269,9 +1438,10 @@ static struct fb_ops sm501fb_ops_pnl = { | |||
1269 | .fb_blank = sm501fb_blank_pnl, | 1438 | .fb_blank = sm501fb_blank_pnl, |
1270 | .fb_setcolreg = sm501fb_setcolreg, | 1439 | .fb_setcolreg = sm501fb_setcolreg, |
1271 | .fb_cursor = sm501fb_cursor, | 1440 | .fb_cursor = sm501fb_cursor, |
1272 | .fb_fillrect = cfb_fillrect, | 1441 | .fb_fillrect = sm501fb_fillrect, |
1273 | .fb_copyarea = cfb_copyarea, | 1442 | .fb_copyarea = sm501fb_copyarea, |
1274 | .fb_imageblit = cfb_imageblit, | 1443 | .fb_imageblit = cfb_imageblit, |
1444 | .fb_sync = sm501fb_sync, | ||
1275 | }; | 1445 | }; |
1276 | 1446 | ||
1277 | /* sm501_init_cursor | 1447 | /* sm501_init_cursor |
@@ -1329,7 +1499,8 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1329 | dev_warn(dev, "no irq for device\n"); | 1499 | dev_warn(dev, "no irq for device\n"); |
1330 | } | 1500 | } |
1331 | 1501 | ||
1332 | /* allocate, reserve and remap resources for registers */ | 1502 | /* allocate, reserve and remap resources for display |
1503 | * controller registers */ | ||
1333 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1504 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1334 | if (res == NULL) { | 1505 | if (res == NULL) { |
1335 | dev_err(dev, "no resource definition for registers\n"); | 1506 | dev_err(dev, "no resource definition for registers\n"); |
@@ -1338,7 +1509,7 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1338 | } | 1509 | } |
1339 | 1510 | ||
1340 | info->regs_res = request_mem_region(res->start, | 1511 | info->regs_res = request_mem_region(res->start, |
1341 | res->end - res->start, | 1512 | resource_size(res), |
1342 | pdev->name); | 1513 | pdev->name); |
1343 | 1514 | ||
1344 | if (info->regs_res == NULL) { | 1515 | if (info->regs_res == NULL) { |
@@ -1347,37 +1518,63 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1347 | goto err_release; | 1518 | goto err_release; |
1348 | } | 1519 | } |
1349 | 1520 | ||
1350 | info->regs = ioremap(res->start, (res->end - res->start)+1); | 1521 | info->regs = ioremap(res->start, resource_size(res)); |
1351 | if (info->regs == NULL) { | 1522 | if (info->regs == NULL) { |
1352 | dev_err(dev, "cannot remap registers\n"); | 1523 | dev_err(dev, "cannot remap registers\n"); |
1353 | ret = -ENXIO; | 1524 | ret = -ENXIO; |
1354 | goto err_regs_res; | 1525 | goto err_regs_res; |
1355 | } | 1526 | } |
1356 | 1527 | ||
1528 | /* allocate, reserve and remap resources for 2d | ||
1529 | * controller registers */ | ||
1530 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1531 | if (res == NULL) { | ||
1532 | dev_err(dev, "no resource definition for 2d registers\n"); | ||
1533 | ret = -ENOENT; | ||
1534 | goto err_regs_map; | ||
1535 | } | ||
1536 | |||
1537 | info->regs2d_res = request_mem_region(res->start, | ||
1538 | resource_size(res), | ||
1539 | pdev->name); | ||
1540 | |||
1541 | if (info->regs2d_res == NULL) { | ||
1542 | dev_err(dev, "cannot claim registers\n"); | ||
1543 | ret = -ENXIO; | ||
1544 | goto err_regs_map; | ||
1545 | } | ||
1546 | |||
1547 | info->regs2d = ioremap(res->start, resource_size(res)); | ||
1548 | if (info->regs2d == NULL) { | ||
1549 | dev_err(dev, "cannot remap registers\n"); | ||
1550 | ret = -ENXIO; | ||
1551 | goto err_regs2d_res; | ||
1552 | } | ||
1553 | |||
1357 | /* allocate, reserve resources for framebuffer */ | 1554 | /* allocate, reserve resources for framebuffer */ |
1358 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | 1555 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); |
1359 | if (res == NULL) { | 1556 | if (res == NULL) { |
1360 | dev_err(dev, "no memory resource defined\n"); | 1557 | dev_err(dev, "no memory resource defined\n"); |
1361 | ret = -ENXIO; | 1558 | ret = -ENXIO; |
1362 | goto err_regs_map; | 1559 | goto err_regs2d_map; |
1363 | } | 1560 | } |
1364 | 1561 | ||
1365 | info->fbmem_res = request_mem_region(res->start, | 1562 | info->fbmem_res = request_mem_region(res->start, |
1366 | (res->end - res->start)+1, | 1563 | resource_size(res), |
1367 | pdev->name); | 1564 | pdev->name); |
1368 | if (info->fbmem_res == NULL) { | 1565 | if (info->fbmem_res == NULL) { |
1369 | dev_err(dev, "cannot claim framebuffer\n"); | 1566 | dev_err(dev, "cannot claim framebuffer\n"); |
1370 | ret = -ENXIO; | 1567 | ret = -ENXIO; |
1371 | goto err_regs_map; | 1568 | goto err_regs2d_map; |
1372 | } | 1569 | } |
1373 | 1570 | ||
1374 | info->fbmem = ioremap(res->start, (res->end - res->start)+1); | 1571 | info->fbmem = ioremap(res->start, resource_size(res)); |
1375 | if (info->fbmem == NULL) { | 1572 | if (info->fbmem == NULL) { |
1376 | dev_err(dev, "cannot remap framebuffer\n"); | 1573 | dev_err(dev, "cannot remap framebuffer\n"); |
1377 | goto err_mem_res; | 1574 | goto err_mem_res; |
1378 | } | 1575 | } |
1379 | 1576 | ||
1380 | info->fbmem_len = (res->end - res->start)+1; | 1577 | info->fbmem_len = resource_size(res); |
1381 | 1578 | ||
1382 | /* clear framebuffer memory - avoids garbage data on unused fb */ | 1579 | /* clear framebuffer memory - avoids garbage data on unused fb */ |
1383 | memset(info->fbmem, 0, info->fbmem_len); | 1580 | memset(info->fbmem, 0, info->fbmem_len); |
@@ -1389,8 +1586,10 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1389 | /* enable display controller */ | 1586 | /* enable display controller */ |
1390 | sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); | 1587 | sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); |
1391 | 1588 | ||
1392 | /* setup cursors */ | 1589 | /* enable 2d controller */ |
1590 | sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1); | ||
1393 | 1591 | ||
1592 | /* setup cursors */ | ||
1394 | sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); | 1593 | sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); |
1395 | sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); | 1594 | sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); |
1396 | 1595 | ||
@@ -1400,6 +1599,13 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1400 | release_resource(info->fbmem_res); | 1599 | release_resource(info->fbmem_res); |
1401 | kfree(info->fbmem_res); | 1600 | kfree(info->fbmem_res); |
1402 | 1601 | ||
1602 | err_regs2d_map: | ||
1603 | iounmap(info->regs2d); | ||
1604 | |||
1605 | err_regs2d_res: | ||
1606 | release_resource(info->regs2d_res); | ||
1607 | kfree(info->regs2d_res); | ||
1608 | |||
1403 | err_regs_map: | 1609 | err_regs_map: |
1404 | iounmap(info->regs); | 1610 | iounmap(info->regs); |
1405 | 1611 | ||
@@ -1420,6 +1626,10 @@ static void sm501fb_stop(struct sm501fb_info *info) | |||
1420 | release_resource(info->fbmem_res); | 1626 | release_resource(info->fbmem_res); |
1421 | kfree(info->fbmem_res); | 1627 | kfree(info->fbmem_res); |
1422 | 1628 | ||
1629 | iounmap(info->regs2d); | ||
1630 | release_resource(info->regs2d_res); | ||
1631 | kfree(info->regs2d_res); | ||
1632 | |||
1423 | iounmap(info->regs); | 1633 | iounmap(info->regs); |
1424 | release_resource(info->regs_res); | 1634 | release_resource(info->regs_res); |
1425 | kfree(info->regs_res); | 1635 | kfree(info->regs_res); |
@@ -1486,7 +1696,8 @@ static int sm501fb_init_fb(struct fb_info *fb, | |||
1486 | par->ops.fb_cursor = NULL; | 1696 | par->ops.fb_cursor = NULL; |
1487 | 1697 | ||
1488 | fb->fbops = &par->ops; | 1698 | fb->fbops = &par->ops; |
1489 | fb->flags = FBINFO_FLAG_DEFAULT | | 1699 | fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST | |
1700 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | | ||
1490 | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; | 1701 | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; |
1491 | 1702 | ||
1492 | /* fixed data */ | 1703 | /* fixed data */ |
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index e3e597f937a5..09353e2b92f6 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c | |||
@@ -1134,45 +1134,33 @@ static void integrated_lvds_enable(struct lvds_setting_information | |||
1134 | *plvds_setting_info, | 1134 | *plvds_setting_info, |
1135 | struct lvds_chip_information *plvds_chip_info) | 1135 | struct lvds_chip_information *plvds_chip_info) |
1136 | { | 1136 | { |
1137 | bool turn_on_first_powersequence = false; | ||
1138 | bool turn_on_second_powersequence = false; | ||
1139 | |||
1140 | DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", | 1137 | DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", |
1141 | plvds_chip_info->output_interface); | 1138 | plvds_chip_info->output_interface); |
1142 | if (plvds_setting_info->lcd_mode == LCD_SPWG) | 1139 | if (plvds_setting_info->lcd_mode == LCD_SPWG) |
1143 | viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); | 1140 | viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); |
1144 | else | 1141 | else |
1145 | viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); | 1142 | viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); |
1146 | if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) | ||
1147 | turn_on_first_powersequence = true; | ||
1148 | if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) | ||
1149 | turn_on_first_powersequence = true; | ||
1150 | if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) | ||
1151 | turn_on_second_powersequence = true; | ||
1152 | |||
1153 | if (turn_on_second_powersequence) { | ||
1154 | /* Use second power sequence control: */ | ||
1155 | |||
1156 | /* Use hardware control power sequence. */ | ||
1157 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); | ||
1158 | |||
1159 | /* Turn on back light. */ | ||
1160 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); | ||
1161 | 1143 | ||
1162 | /* Turn on hardware power sequence. */ | 1144 | switch (plvds_chip_info->output_interface) { |
1163 | viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); | 1145 | case INTERFACE_LVDS0LVDS1: |
1164 | } | 1146 | case INTERFACE_LVDS0: |
1165 | if (turn_on_first_powersequence) { | ||
1166 | /* Use first power sequence control: */ | 1147 | /* Use first power sequence control: */ |
1167 | |||
1168 | /* Use hardware control power sequence. */ | 1148 | /* Use hardware control power sequence. */ |
1169 | viafb_write_reg_mask(CR91, VIACR, 0, BIT0); | 1149 | viafb_write_reg_mask(CR91, VIACR, 0, BIT0); |
1170 | |||
1171 | /* Turn on back light. */ | 1150 | /* Turn on back light. */ |
1172 | viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); | 1151 | viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); |
1173 | |||
1174 | /* Turn on hardware power sequence. */ | 1152 | /* Turn on hardware power sequence. */ |
1175 | viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); | 1153 | viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); |
1154 | break; | ||
1155 | case INTERFACE_LVDS1: | ||
1156 | /* Use second power sequence control: */ | ||
1157 | /* Use hardware control power sequence. */ | ||
1158 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); | ||
1159 | /* Turn on back light. */ | ||
1160 | viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); | ||
1161 | /* Turn on hardware power sequence. */ | ||
1162 | viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); | ||
1163 | break; | ||
1176 | } | 1164 | } |
1177 | 1165 | ||
1178 | /* Turn DFP High/Low pad on. */ | 1166 | /* Turn DFP High/Low pad on. */ |
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 56ec696e8afa..10d8c4b4baeb 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
@@ -1797,7 +1797,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { | |||
1797 | static void viafb_init_proc(struct proc_dir_entry **viafb_entry) | 1797 | static void viafb_init_proc(struct proc_dir_entry **viafb_entry) |
1798 | { | 1798 | { |
1799 | *viafb_entry = proc_mkdir("viafb", NULL); | 1799 | *viafb_entry = proc_mkdir("viafb", NULL); |
1800 | if (viafb_entry) { | 1800 | if (*viafb_entry) { |
1801 | proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); | 1801 | proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); |
1802 | proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); | 1802 | proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); |
1803 | proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); | 1803 | proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); |
@@ -711,10 +711,8 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) | |||
711 | */ | 711 | */ |
712 | ret = retry(iocb); | 712 | ret = retry(iocb); |
713 | 713 | ||
714 | if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { | 714 | if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) |
715 | BUG_ON(!list_empty(&iocb->ki_wait.task_list)); | ||
716 | aio_complete(iocb, ret, 0); | 715 | aio_complete(iocb, ret, 0); |
717 | } | ||
718 | out: | 716 | out: |
719 | spin_lock_irq(&ctx->ctx_lock); | 717 | spin_lock_irq(&ctx->ctx_lock); |
720 | 718 | ||
@@ -866,13 +864,6 @@ static void try_queue_kicked_iocb(struct kiocb *iocb) | |||
866 | unsigned long flags; | 864 | unsigned long flags; |
867 | int run = 0; | 865 | int run = 0; |
868 | 866 | ||
869 | /* We're supposed to be the only path putting the iocb back on the run | ||
870 | * list. If we find that the iocb is *back* on a wait queue already | ||
871 | * than retry has happened before we could queue the iocb. This also | ||
872 | * means that the retry could have completed and freed our iocb, no | ||
873 | * good. */ | ||
874 | BUG_ON((!list_empty(&iocb->ki_wait.task_list))); | ||
875 | |||
876 | spin_lock_irqsave(&ctx->ctx_lock, flags); | 867 | spin_lock_irqsave(&ctx->ctx_lock, flags); |
877 | /* set this inside the lock so that we can't race with aio_run_iocb() | 868 | /* set this inside the lock so that we can't race with aio_run_iocb() |
878 | * testing it and putting the iocb on the run list under the lock */ | 869 | * testing it and putting the iocb on the run list under the lock */ |
@@ -886,7 +877,7 @@ static void try_queue_kicked_iocb(struct kiocb *iocb) | |||
886 | /* | 877 | /* |
887 | * kick_iocb: | 878 | * kick_iocb: |
888 | * Called typically from a wait queue callback context | 879 | * Called typically from a wait queue callback context |
889 | * (aio_wake_function) to trigger a retry of the iocb. | 880 | * to trigger a retry of the iocb. |
890 | * The retry is usually executed by aio workqueue | 881 | * The retry is usually executed by aio workqueue |
891 | * threads (See aio_kick_handler). | 882 | * threads (See aio_kick_handler). |
892 | */ | 883 | */ |
@@ -1520,31 +1511,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) | |||
1520 | return 0; | 1511 | return 0; |
1521 | } | 1512 | } |
1522 | 1513 | ||
1523 | /* | ||
1524 | * aio_wake_function: | ||
1525 | * wait queue callback function for aio notification, | ||
1526 | * Simply triggers a retry of the operation via kick_iocb. | ||
1527 | * | ||
1528 | * This callback is specified in the wait queue entry in | ||
1529 | * a kiocb. | ||
1530 | * | ||
1531 | * Note: | ||
1532 | * This routine is executed with the wait queue lock held. | ||
1533 | * Since kick_iocb acquires iocb->ctx->ctx_lock, it nests | ||
1534 | * the ioctx lock inside the wait queue lock. This is safe | ||
1535 | * because this callback isn't used for wait queues which | ||
1536 | * are nested inside ioctx lock (i.e. ctx->wait) | ||
1537 | */ | ||
1538 | static int aio_wake_function(wait_queue_t *wait, unsigned mode, | ||
1539 | int sync, void *key) | ||
1540 | { | ||
1541 | struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait); | ||
1542 | |||
1543 | list_del_init(&wait->task_list); | ||
1544 | kick_iocb(iocb); | ||
1545 | return 1; | ||
1546 | } | ||
1547 | |||
1548 | static void aio_batch_add(struct address_space *mapping, | 1514 | static void aio_batch_add(struct address_space *mapping, |
1549 | struct hlist_head *batch_hash) | 1515 | struct hlist_head *batch_hash) |
1550 | { | 1516 | { |
@@ -1642,8 +1608,6 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1642 | req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf; | 1608 | req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf; |
1643 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; | 1609 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; |
1644 | req->ki_opcode = iocb->aio_lio_opcode; | 1610 | req->ki_opcode = iocb->aio_lio_opcode; |
1645 | init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); | ||
1646 | INIT_LIST_HEAD(&req->ki_wait.task_list); | ||
1647 | 1611 | ||
1648 | ret = aio_setup_iocb(req); | 1612 | ret = aio_setup_iocb(req); |
1649 | 1613 | ||
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 8f7cdde41733..0118d67221b2 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -60,6 +60,11 @@ do { \ | |||
60 | current->pid, __func__, ##args); \ | 60 | current->pid, __func__, ##args); \ |
61 | } while (0) | 61 | } while (0) |
62 | 62 | ||
63 | struct rehash_entry { | ||
64 | struct task_struct *task; | ||
65 | struct list_head list; | ||
66 | }; | ||
67 | |||
63 | /* Unified info structure. This is pointed to by both the dentry and | 68 | /* Unified info structure. This is pointed to by both the dentry and |
64 | inode structures. Each file in the filesystem has an instance of this | 69 | inode structures. Each file in the filesystem has an instance of this |
65 | structure. It holds a reference to the dentry, so dentries are never | 70 | structure. It holds a reference to the dentry, so dentries are never |
@@ -75,6 +80,9 @@ struct autofs_info { | |||
75 | struct completion expire_complete; | 80 | struct completion expire_complete; |
76 | 81 | ||
77 | struct list_head active; | 82 | struct list_head active; |
83 | int active_count; | ||
84 | struct list_head rehash_list; | ||
85 | |||
78 | struct list_head expiring; | 86 | struct list_head expiring; |
79 | 87 | ||
80 | struct autofs_sb_info *sbi; | 88 | struct autofs_sb_info *sbi; |
@@ -95,6 +103,8 @@ struct autofs_info { | |||
95 | 103 | ||
96 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ | 104 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ |
97 | #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ | 105 | #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ |
106 | #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ | ||
107 | #define AUTOFS_INF_REHASH (1<<3) /* dentry in transit to ->lookup() */ | ||
98 | 108 | ||
99 | struct autofs_wait_queue { | 109 | struct autofs_wait_queue { |
100 | wait_queue_head_t queue; | 110 | wait_queue_head_t queue; |
@@ -161,7 +171,7 @@ static inline int autofs4_ispending(struct dentry *dentry) | |||
161 | { | 171 | { |
162 | struct autofs_info *inf = autofs4_dentry_ino(dentry); | 172 | struct autofs_info *inf = autofs4_dentry_ino(dentry); |
163 | 173 | ||
164 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) | 174 | if (inf->flags & AUTOFS_INF_PENDING) |
165 | return 1; | 175 | return 1; |
166 | 176 | ||
167 | if (inf->flags & AUTOFS_INF_EXPIRING) | 177 | if (inf->flags & AUTOFS_INF_EXPIRING) |
@@ -264,5 +274,31 @@ out: | |||
264 | return ret; | 274 | return ret; |
265 | } | 275 | } |
266 | 276 | ||
277 | static inline void autofs4_add_expiring(struct dentry *dentry) | ||
278 | { | ||
279 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
280 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
281 | if (ino) { | ||
282 | spin_lock(&sbi->lookup_lock); | ||
283 | if (list_empty(&ino->expiring)) | ||
284 | list_add(&ino->expiring, &sbi->expiring_list); | ||
285 | spin_unlock(&sbi->lookup_lock); | ||
286 | } | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | static inline void autofs4_del_expiring(struct dentry *dentry) | ||
291 | { | ||
292 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
293 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
294 | if (ino) { | ||
295 | spin_lock(&sbi->lookup_lock); | ||
296 | if (!list_empty(&ino->expiring)) | ||
297 | list_del_init(&ino->expiring); | ||
298 | spin_unlock(&sbi->lookup_lock); | ||
299 | } | ||
300 | return; | ||
301 | } | ||
302 | |||
267 | void autofs4_dentry_release(struct dentry *); | 303 | void autofs4_dentry_release(struct dentry *); |
268 | extern void autofs4_kill_sb(struct super_block *); | 304 | extern void autofs4_kill_sb(struct super_block *); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 3da18d453488..74bc9aa6df31 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -27,7 +27,7 @@ static inline int autofs4_can_expire(struct dentry *dentry, | |||
27 | return 0; | 27 | return 0; |
28 | 28 | ||
29 | /* No point expiring a pending mount */ | 29 | /* No point expiring a pending mount */ |
30 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) | 30 | if (ino->flags & AUTOFS_INF_PENDING) |
31 | return 0; | 31 | return 0; |
32 | 32 | ||
33 | if (!do_now) { | 33 | if (!do_now) { |
@@ -279,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
279 | root->d_mounted--; | 279 | root->d_mounted--; |
280 | } | 280 | } |
281 | ino->flags |= AUTOFS_INF_EXPIRING; | 281 | ino->flags |= AUTOFS_INF_EXPIRING; |
282 | autofs4_add_expiring(root); | ||
282 | init_completion(&ino->expire_complete); | 283 | init_completion(&ino->expire_complete); |
283 | spin_unlock(&sbi->fs_lock); | 284 | spin_unlock(&sbi->fs_lock); |
284 | return root; | 285 | return root; |
@@ -406,6 +407,7 @@ found: | |||
406 | expired, (int)expired->d_name.len, expired->d_name.name); | 407 | expired, (int)expired->d_name.len, expired->d_name.name); |
407 | ino = autofs4_dentry_ino(expired); | 408 | ino = autofs4_dentry_ino(expired); |
408 | ino->flags |= AUTOFS_INF_EXPIRING; | 409 | ino->flags |= AUTOFS_INF_EXPIRING; |
410 | autofs4_add_expiring(expired); | ||
409 | init_completion(&ino->expire_complete); | 411 | init_completion(&ino->expire_complete); |
410 | spin_unlock(&sbi->fs_lock); | 412 | spin_unlock(&sbi->fs_lock); |
411 | spin_lock(&dcache_lock); | 413 | spin_lock(&dcache_lock); |
@@ -433,7 +435,7 @@ int autofs4_expire_wait(struct dentry *dentry) | |||
433 | 435 | ||
434 | DPRINTK("expire done status=%d", status); | 436 | DPRINTK("expire done status=%d", status); |
435 | 437 | ||
436 | if (d_unhashed(dentry)) | 438 | if (d_unhashed(dentry) && IS_DEADDIR(dentry->d_inode)) |
437 | return -EAGAIN; | 439 | return -EAGAIN; |
438 | 440 | ||
439 | return status; | 441 | return status; |
@@ -473,6 +475,7 @@ int autofs4_expire_run(struct super_block *sb, | |||
473 | spin_lock(&sbi->fs_lock); | 475 | spin_lock(&sbi->fs_lock); |
474 | ino = autofs4_dentry_ino(dentry); | 476 | ino = autofs4_dentry_ino(dentry); |
475 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 477 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
478 | autofs4_del_expiring(dentry); | ||
476 | complete_all(&ino->expire_complete); | 479 | complete_all(&ino->expire_complete); |
477 | spin_unlock(&sbi->fs_lock); | 480 | spin_unlock(&sbi->fs_lock); |
478 | 481 | ||
@@ -503,6 +506,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
503 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | 506 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; |
504 | } | 507 | } |
505 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 508 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
509 | autofs4_del_expiring(dentry); | ||
506 | complete_all(&ino->expire_complete); | 510 | complete_all(&ino->expire_complete); |
507 | spin_unlock(&sbi->fs_lock); | 511 | spin_unlock(&sbi->fs_lock); |
508 | dput(dentry); | 512 | dput(dentry); |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 69c8142da838..d0a3de247458 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -49,6 +49,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
49 | ino->dentry = NULL; | 49 | ino->dentry = NULL; |
50 | ino->size = 0; | 50 | ino->size = 0; |
51 | INIT_LIST_HEAD(&ino->active); | 51 | INIT_LIST_HEAD(&ino->active); |
52 | INIT_LIST_HEAD(&ino->rehash_list); | ||
53 | ino->active_count = 0; | ||
52 | INIT_LIST_HEAD(&ino->expiring); | 54 | INIT_LIST_HEAD(&ino->expiring); |
53 | atomic_set(&ino->count, 0); | 55 | atomic_set(&ino->count, 0); |
54 | } | 56 | } |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index b96a3c57359d..30cc9ddf4b70 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -72,6 +72,139 @@ const struct inode_operations autofs4_dir_inode_operations = { | |||
72 | .rmdir = autofs4_dir_rmdir, | 72 | .rmdir = autofs4_dir_rmdir, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static void autofs4_add_active(struct dentry *dentry) | ||
76 | { | ||
77 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
78 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
79 | if (ino) { | ||
80 | spin_lock(&sbi->lookup_lock); | ||
81 | if (!ino->active_count) { | ||
82 | if (list_empty(&ino->active)) | ||
83 | list_add(&ino->active, &sbi->active_list); | ||
84 | } | ||
85 | ino->active_count++; | ||
86 | spin_unlock(&sbi->lookup_lock); | ||
87 | } | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | static void autofs4_del_active(struct dentry *dentry) | ||
92 | { | ||
93 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
94 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
95 | if (ino) { | ||
96 | spin_lock(&sbi->lookup_lock); | ||
97 | ino->active_count--; | ||
98 | if (!ino->active_count) { | ||
99 | if (!list_empty(&ino->active)) | ||
100 | list_del_init(&ino->active); | ||
101 | } | ||
102 | spin_unlock(&sbi->lookup_lock); | ||
103 | } | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | static void autofs4_add_rehash_entry(struct autofs_info *ino, | ||
108 | struct rehash_entry *entry) | ||
109 | { | ||
110 | entry->task = current; | ||
111 | INIT_LIST_HEAD(&entry->list); | ||
112 | list_add(&entry->list, &ino->rehash_list); | ||
113 | return; | ||
114 | } | ||
115 | |||
116 | static void autofs4_remove_rehash_entry(struct autofs_info *ino) | ||
117 | { | ||
118 | struct list_head *head = &ino->rehash_list; | ||
119 | struct rehash_entry *entry; | ||
120 | list_for_each_entry(entry, head, list) { | ||
121 | if (entry->task == current) { | ||
122 | list_del(&entry->list); | ||
123 | kfree(entry); | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | static void autofs4_remove_rehash_entrys(struct autofs_info *ino) | ||
131 | { | ||
132 | struct autofs_sb_info *sbi = ino->sbi; | ||
133 | struct rehash_entry *entry, *next; | ||
134 | struct list_head *head; | ||
135 | |||
136 | spin_lock(&sbi->fs_lock); | ||
137 | spin_lock(&sbi->lookup_lock); | ||
138 | if (!(ino->flags & AUTOFS_INF_REHASH)) { | ||
139 | spin_unlock(&sbi->lookup_lock); | ||
140 | spin_unlock(&sbi->fs_lock); | ||
141 | return; | ||
142 | } | ||
143 | ino->flags &= ~AUTOFS_INF_REHASH; | ||
144 | head = &ino->rehash_list; | ||
145 | list_for_each_entry_safe(entry, next, head, list) { | ||
146 | list_del(&entry->list); | ||
147 | kfree(entry); | ||
148 | } | ||
149 | spin_unlock(&sbi->lookup_lock); | ||
150 | spin_unlock(&sbi->fs_lock); | ||
151 | dput(ino->dentry); | ||
152 | |||
153 | return; | ||
154 | } | ||
155 | |||
156 | static void autofs4_revalidate_drop(struct dentry *dentry, | ||
157 | struct rehash_entry *entry) | ||
158 | { | ||
159 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
160 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
161 | /* | ||
162 | * Add to the active list so we can pick this up in | ||
163 | * ->lookup(). Also add an entry to a rehash list so | ||
164 | * we know when there are no dentrys in flight so we | ||
165 | * know when we can rehash the dentry. | ||
166 | */ | ||
167 | spin_lock(&sbi->lookup_lock); | ||
168 | if (list_empty(&ino->active)) | ||
169 | list_add(&ino->active, &sbi->active_list); | ||
170 | autofs4_add_rehash_entry(ino, entry); | ||
171 | spin_unlock(&sbi->lookup_lock); | ||
172 | if (!(ino->flags & AUTOFS_INF_REHASH)) { | ||
173 | ino->flags |= AUTOFS_INF_REHASH; | ||
174 | dget(dentry); | ||
175 | spin_lock(&dentry->d_lock); | ||
176 | __d_drop(dentry); | ||
177 | spin_unlock(&dentry->d_lock); | ||
178 | } | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | static void autofs4_revalidate_rehash(struct dentry *dentry) | ||
183 | { | ||
184 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
185 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
186 | if (ino->flags & AUTOFS_INF_REHASH) { | ||
187 | spin_lock(&sbi->lookup_lock); | ||
188 | autofs4_remove_rehash_entry(ino); | ||
189 | if (list_empty(&ino->rehash_list)) { | ||
190 | spin_unlock(&sbi->lookup_lock); | ||
191 | ino->flags &= ~AUTOFS_INF_REHASH; | ||
192 | d_rehash(dentry); | ||
193 | dput(ino->dentry); | ||
194 | } else | ||
195 | spin_unlock(&sbi->lookup_lock); | ||
196 | } | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | static unsigned int autofs4_need_mount(unsigned int flags) | ||
201 | { | ||
202 | unsigned int res = 0; | ||
203 | if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS)) | ||
204 | res = 1; | ||
205 | return res; | ||
206 | } | ||
207 | |||
75 | static int autofs4_dir_open(struct inode *inode, struct file *file) | 208 | static int autofs4_dir_open(struct inode *inode, struct file *file) |
76 | { | 209 | { |
77 | struct dentry *dentry = file->f_path.dentry; | 210 | struct dentry *dentry = file->f_path.dentry; |
@@ -93,7 +226,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
93 | * it. | 226 | * it. |
94 | */ | 227 | */ |
95 | spin_lock(&dcache_lock); | 228 | spin_lock(&dcache_lock); |
96 | if (!d_mountpoint(dentry) && __simple_empty(dentry)) { | 229 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
97 | spin_unlock(&dcache_lock); | 230 | spin_unlock(&dcache_lock); |
98 | return -ENOENT; | 231 | return -ENOENT; |
99 | } | 232 | } |
@@ -103,7 +236,7 @@ out: | |||
103 | return dcache_dir_open(inode, file); | 236 | return dcache_dir_open(inode, file); |
104 | } | 237 | } |
105 | 238 | ||
106 | static int try_to_fill_dentry(struct dentry *dentry, int flags) | 239 | static int try_to_fill_dentry(struct dentry *dentry) |
107 | { | 240 | { |
108 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 241 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
109 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 242 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
@@ -116,55 +249,17 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
116 | * Wait for a pending mount, triggering one if there | 249 | * Wait for a pending mount, triggering one if there |
117 | * isn't one already | 250 | * isn't one already |
118 | */ | 251 | */ |
119 | if (dentry->d_inode == NULL) { | 252 | DPRINTK("waiting for mount name=%.*s", |
120 | DPRINTK("waiting for mount name=%.*s", | 253 | dentry->d_name.len, dentry->d_name.name); |
121 | dentry->d_name.len, dentry->d_name.name); | ||
122 | |||
123 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
124 | |||
125 | DPRINTK("mount done status=%d", status); | ||
126 | |||
127 | /* Turn this into a real negative dentry? */ | ||
128 | if (status == -ENOENT) { | ||
129 | spin_lock(&dentry->d_lock); | ||
130 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | ||
131 | spin_unlock(&dentry->d_lock); | ||
132 | return status; | ||
133 | } else if (status) { | ||
134 | /* Return a negative dentry, but leave it "pending" */ | ||
135 | return status; | ||
136 | } | ||
137 | /* Trigger mount for path component or follow link */ | ||
138 | } else if (dentry->d_flags & DCACHE_AUTOFS_PENDING || | ||
139 | flags & (TRIGGER_FLAGS | TRIGGER_INTENTS) || | ||
140 | current->link_count) { | ||
141 | DPRINTK("waiting for mount name=%.*s", | ||
142 | dentry->d_name.len, dentry->d_name.name); | ||
143 | |||
144 | spin_lock(&dentry->d_lock); | ||
145 | dentry->d_flags |= DCACHE_AUTOFS_PENDING; | ||
146 | spin_unlock(&dentry->d_lock); | ||
147 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
148 | 254 | ||
149 | DPRINTK("mount done status=%d", status); | 255 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); |
150 | 256 | ||
151 | if (status) { | 257 | DPRINTK("mount done status=%d", status); |
152 | spin_lock(&dentry->d_lock); | ||
153 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | ||
154 | spin_unlock(&dentry->d_lock); | ||
155 | return status; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* Initialize expiry counter after successful mount */ | ||
160 | if (ino) | ||
161 | ino->last_used = jiffies; | ||
162 | 258 | ||
163 | spin_lock(&dentry->d_lock); | 259 | /* Update expiry counter */ |
164 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 260 | ino->last_used = jiffies; |
165 | spin_unlock(&dentry->d_lock); | ||
166 | 261 | ||
167 | return 0; | 262 | return status; |
168 | } | 263 | } |
169 | 264 | ||
170 | /* For autofs direct mounts the follow link triggers the mount */ | 265 | /* For autofs direct mounts the follow link triggers the mount */ |
@@ -202,27 +297,39 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
202 | autofs4_expire_wait(dentry); | 297 | autofs4_expire_wait(dentry); |
203 | 298 | ||
204 | /* We trigger a mount for almost all flags */ | 299 | /* We trigger a mount for almost all flags */ |
205 | lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); | 300 | lookup_type = autofs4_need_mount(nd->flags); |
206 | if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) | 301 | spin_lock(&sbi->fs_lock); |
302 | spin_lock(&dcache_lock); | ||
303 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | ||
304 | spin_unlock(&dcache_lock); | ||
305 | spin_unlock(&sbi->fs_lock); | ||
207 | goto follow; | 306 | goto follow; |
307 | } | ||
208 | 308 | ||
209 | /* | 309 | /* |
210 | * If the dentry contains directories then it is an autofs | 310 | * If the dentry contains directories then it is an autofs |
211 | * multi-mount with no root mount offset. So don't try to | 311 | * multi-mount with no root mount offset. So don't try to |
212 | * mount it again. | 312 | * mount it again. |
213 | */ | 313 | */ |
214 | spin_lock(&dcache_lock); | 314 | if (ino->flags & AUTOFS_INF_PENDING || |
215 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING || | 315 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
216 | (!d_mountpoint(dentry) && __simple_empty(dentry))) { | 316 | ino->flags |= AUTOFS_INF_PENDING; |
217 | spin_unlock(&dcache_lock); | 317 | spin_unlock(&dcache_lock); |
318 | spin_unlock(&sbi->fs_lock); | ||
319 | |||
320 | status = try_to_fill_dentry(dentry); | ||
321 | |||
322 | spin_lock(&sbi->fs_lock); | ||
323 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
324 | spin_unlock(&sbi->fs_lock); | ||
218 | 325 | ||
219 | status = try_to_fill_dentry(dentry, 0); | ||
220 | if (status) | 326 | if (status) |
221 | goto out_error; | 327 | goto out_error; |
222 | 328 | ||
223 | goto follow; | 329 | goto follow; |
224 | } | 330 | } |
225 | spin_unlock(&dcache_lock); | 331 | spin_unlock(&dcache_lock); |
332 | spin_unlock(&sbi->fs_lock); | ||
226 | follow: | 333 | follow: |
227 | /* | 334 | /* |
228 | * If there is no root mount it must be an autofs | 335 | * If there is no root mount it must be an autofs |
@@ -254,18 +361,47 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
254 | { | 361 | { |
255 | struct inode *dir = dentry->d_parent->d_inode; | 362 | struct inode *dir = dentry->d_parent->d_inode; |
256 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 363 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
257 | int oz_mode = autofs4_oz_mode(sbi); | 364 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
365 | struct rehash_entry *entry; | ||
258 | int flags = nd ? nd->flags : 0; | 366 | int flags = nd ? nd->flags : 0; |
259 | int status = 1; | 367 | unsigned int mutex_aquired; |
368 | |||
369 | DPRINTK("name = %.*s oz_mode = %d", | ||
370 | dentry->d_name.len, dentry->d_name.name, oz_mode); | ||
371 | |||
372 | /* Daemon never causes a mount to trigger */ | ||
373 | if (autofs4_oz_mode(sbi)) | ||
374 | return 1; | ||
375 | |||
376 | entry = kmalloc(sizeof(struct rehash_entry), GFP_KERNEL); | ||
377 | if (!entry) | ||
378 | return -ENOMEM; | ||
379 | |||
380 | mutex_aquired = mutex_trylock(&dir->i_mutex); | ||
260 | 381 | ||
261 | /* Pending dentry */ | ||
262 | spin_lock(&sbi->fs_lock); | 382 | spin_lock(&sbi->fs_lock); |
383 | spin_lock(&dcache_lock); | ||
384 | /* Pending dentry */ | ||
263 | if (autofs4_ispending(dentry)) { | 385 | if (autofs4_ispending(dentry)) { |
264 | /* The daemon never causes a mount to trigger */ | 386 | int status; |
265 | spin_unlock(&sbi->fs_lock); | ||
266 | 387 | ||
267 | if (oz_mode) | 388 | /* |
268 | return 1; | 389 | * We can only unhash and send this to ->lookup() if |
390 | * the directory mutex is held over d_revalidate() and | ||
391 | * ->lookup(). This prevents the VFS from incorrectly | ||
392 | * seeing the dentry as non-existent. | ||
393 | */ | ||
394 | ino->flags |= AUTOFS_INF_PENDING; | ||
395 | if (!mutex_aquired) { | ||
396 | autofs4_revalidate_drop(dentry, entry); | ||
397 | spin_unlock(&dcache_lock); | ||
398 | spin_unlock(&sbi->fs_lock); | ||
399 | return 0; | ||
400 | } | ||
401 | spin_unlock(&dcache_lock); | ||
402 | spin_unlock(&sbi->fs_lock); | ||
403 | mutex_unlock(&dir->i_mutex); | ||
404 | kfree(entry); | ||
269 | 405 | ||
270 | /* | 406 | /* |
271 | * If the directory has gone away due to an expire | 407 | * If the directory has gone away due to an expire |
@@ -279,46 +415,82 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
279 | * A zero status is success otherwise we have a | 415 | * A zero status is success otherwise we have a |
280 | * negative error code. | 416 | * negative error code. |
281 | */ | 417 | */ |
282 | status = try_to_fill_dentry(dentry, flags); | 418 | status = try_to_fill_dentry(dentry); |
419 | |||
420 | spin_lock(&sbi->fs_lock); | ||
421 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
422 | spin_unlock(&sbi->fs_lock); | ||
423 | |||
283 | if (status == 0) | 424 | if (status == 0) |
284 | return 1; | 425 | return 1; |
285 | 426 | ||
286 | return status; | 427 | return status; |
287 | } | 428 | } |
288 | spin_unlock(&sbi->fs_lock); | ||
289 | |||
290 | /* Negative dentry.. invalidate if "old" */ | ||
291 | if (dentry->d_inode == NULL) | ||
292 | return 0; | ||
293 | 429 | ||
294 | /* Check for a non-mountpoint directory with no contents */ | 430 | /* Check for a non-mountpoint directory with no contents */ |
295 | spin_lock(&dcache_lock); | ||
296 | if (S_ISDIR(dentry->d_inode->i_mode) && | 431 | if (S_ISDIR(dentry->d_inode->i_mode) && |
297 | !d_mountpoint(dentry) && | 432 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
298 | __simple_empty(dentry)) { | ||
299 | DPRINTK("dentry=%p %.*s, emptydir", | 433 | DPRINTK("dentry=%p %.*s, emptydir", |
300 | dentry, dentry->d_name.len, dentry->d_name.name); | 434 | dentry, dentry->d_name.len, dentry->d_name.name); |
301 | spin_unlock(&dcache_lock); | ||
302 | 435 | ||
303 | /* The daemon never causes a mount to trigger */ | 436 | if (autofs4_need_mount(flags) || current->link_count) { |
304 | if (oz_mode) | 437 | int status; |
305 | return 1; | ||
306 | 438 | ||
307 | /* | 439 | /* |
308 | * A zero status is success otherwise we have a | 440 | * We can only unhash and send this to ->lookup() if |
309 | * negative error code. | 441 | * the directory mutex is held over d_revalidate() and |
310 | */ | 442 | * ->lookup(). This prevents the VFS from incorrectly |
311 | status = try_to_fill_dentry(dentry, flags); | 443 | * seeing the dentry as non-existent. |
312 | if (status == 0) | 444 | */ |
313 | return 1; | 445 | ino->flags |= AUTOFS_INF_PENDING; |
446 | if (!mutex_aquired) { | ||
447 | autofs4_revalidate_drop(dentry, entry); | ||
448 | spin_unlock(&dcache_lock); | ||
449 | spin_unlock(&sbi->fs_lock); | ||
450 | return 0; | ||
451 | } | ||
452 | spin_unlock(&dcache_lock); | ||
453 | spin_unlock(&sbi->fs_lock); | ||
454 | mutex_unlock(&dir->i_mutex); | ||
455 | kfree(entry); | ||
314 | 456 | ||
315 | return status; | 457 | /* |
458 | * A zero status is success otherwise we have a | ||
459 | * negative error code. | ||
460 | */ | ||
461 | status = try_to_fill_dentry(dentry); | ||
462 | |||
463 | spin_lock(&sbi->fs_lock); | ||
464 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
465 | spin_unlock(&sbi->fs_lock); | ||
466 | |||
467 | if (status == 0) | ||
468 | return 1; | ||
469 | |||
470 | return status; | ||
471 | } | ||
316 | } | 472 | } |
317 | spin_unlock(&dcache_lock); | 473 | spin_unlock(&dcache_lock); |
474 | spin_unlock(&sbi->fs_lock); | ||
475 | |||
476 | if (mutex_aquired) | ||
477 | mutex_unlock(&dir->i_mutex); | ||
478 | |||
479 | kfree(entry); | ||
318 | 480 | ||
319 | return 1; | 481 | return 1; |
320 | } | 482 | } |
321 | 483 | ||
484 | static void autofs4_free_rehash_entrys(struct autofs_info *inf) | ||
485 | { | ||
486 | struct list_head *head = &inf->rehash_list; | ||
487 | struct rehash_entry *entry, *next; | ||
488 | list_for_each_entry_safe(entry, next, head, list) { | ||
489 | list_del(&entry->list); | ||
490 | kfree(entry); | ||
491 | } | ||
492 | } | ||
493 | |||
322 | void autofs4_dentry_release(struct dentry *de) | 494 | void autofs4_dentry_release(struct dentry *de) |
323 | { | 495 | { |
324 | struct autofs_info *inf; | 496 | struct autofs_info *inf; |
@@ -337,6 +509,8 @@ void autofs4_dentry_release(struct dentry *de) | |||
337 | list_del(&inf->active); | 509 | list_del(&inf->active); |
338 | if (!list_empty(&inf->expiring)) | 510 | if (!list_empty(&inf->expiring)) |
339 | list_del(&inf->expiring); | 511 | list_del(&inf->expiring); |
512 | if (!list_empty(&inf->rehash_list)) | ||
513 | autofs4_free_rehash_entrys(inf); | ||
340 | spin_unlock(&sbi->lookup_lock); | 514 | spin_unlock(&sbi->lookup_lock); |
341 | } | 515 | } |
342 | 516 | ||
@@ -359,35 +533,52 @@ static const struct dentry_operations autofs4_dentry_operations = { | |||
359 | .d_release = autofs4_dentry_release, | 533 | .d_release = autofs4_dentry_release, |
360 | }; | 534 | }; |
361 | 535 | ||
362 | static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) | 536 | static struct dentry *autofs4_lookup_active(struct dentry *dentry) |
363 | { | 537 | { |
538 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
539 | struct dentry *parent = dentry->d_parent; | ||
540 | struct qstr *name = &dentry->d_name; | ||
364 | unsigned int len = name->len; | 541 | unsigned int len = name->len; |
365 | unsigned int hash = name->hash; | 542 | unsigned int hash = name->hash; |
366 | const unsigned char *str = name->name; | 543 | const unsigned char *str = name->name; |
367 | struct list_head *p, *head; | 544 | struct list_head *p, *head; |
368 | 545 | ||
546 | restart: | ||
369 | spin_lock(&dcache_lock); | 547 | spin_lock(&dcache_lock); |
370 | spin_lock(&sbi->lookup_lock); | 548 | spin_lock(&sbi->lookup_lock); |
371 | head = &sbi->active_list; | 549 | head = &sbi->active_list; |
372 | list_for_each(p, head) { | 550 | list_for_each(p, head) { |
373 | struct autofs_info *ino; | 551 | struct autofs_info *ino; |
374 | struct dentry *dentry; | 552 | struct dentry *active; |
375 | struct qstr *qstr; | 553 | struct qstr *qstr; |
376 | 554 | ||
377 | ino = list_entry(p, struct autofs_info, active); | 555 | ino = list_entry(p, struct autofs_info, active); |
378 | dentry = ino->dentry; | 556 | active = ino->dentry; |
379 | 557 | ||
380 | spin_lock(&dentry->d_lock); | 558 | spin_lock(&active->d_lock); |
381 | 559 | ||
382 | /* Already gone? */ | 560 | /* Already gone? */ |
383 | if (atomic_read(&dentry->d_count) == 0) | 561 | if (atomic_read(&active->d_count) == 0) |
384 | goto next; | 562 | goto next; |
385 | 563 | ||
386 | qstr = &dentry->d_name; | 564 | if (active->d_inode && IS_DEADDIR(active->d_inode)) { |
565 | if (!list_empty(&ino->rehash_list)) { | ||
566 | dget(active); | ||
567 | spin_unlock(&active->d_lock); | ||
568 | spin_unlock(&sbi->lookup_lock); | ||
569 | spin_unlock(&dcache_lock); | ||
570 | autofs4_remove_rehash_entrys(ino); | ||
571 | dput(active); | ||
572 | goto restart; | ||
573 | } | ||
574 | goto next; | ||
575 | } | ||
576 | |||
577 | qstr = &active->d_name; | ||
387 | 578 | ||
388 | if (dentry->d_name.hash != hash) | 579 | if (active->d_name.hash != hash) |
389 | goto next; | 580 | goto next; |
390 | if (dentry->d_parent != parent) | 581 | if (active->d_parent != parent) |
391 | goto next; | 582 | goto next; |
392 | 583 | ||
393 | if (qstr->len != len) | 584 | if (qstr->len != len) |
@@ -395,15 +586,13 @@ static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct d | |||
395 | if (memcmp(qstr->name, str, len)) | 586 | if (memcmp(qstr->name, str, len)) |
396 | goto next; | 587 | goto next; |
397 | 588 | ||
398 | if (d_unhashed(dentry)) { | 589 | dget(active); |
399 | dget(dentry); | 590 | spin_unlock(&active->d_lock); |
400 | spin_unlock(&dentry->d_lock); | 591 | spin_unlock(&sbi->lookup_lock); |
401 | spin_unlock(&sbi->lookup_lock); | 592 | spin_unlock(&dcache_lock); |
402 | spin_unlock(&dcache_lock); | 593 | return active; |
403 | return dentry; | ||
404 | } | ||
405 | next: | 594 | next: |
406 | spin_unlock(&dentry->d_lock); | 595 | spin_unlock(&active->d_lock); |
407 | } | 596 | } |
408 | spin_unlock(&sbi->lookup_lock); | 597 | spin_unlock(&sbi->lookup_lock); |
409 | spin_unlock(&dcache_lock); | 598 | spin_unlock(&dcache_lock); |
@@ -411,8 +600,11 @@ next: | |||
411 | return NULL; | 600 | return NULL; |
412 | } | 601 | } |
413 | 602 | ||
414 | static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) | 603 | static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) |
415 | { | 604 | { |
605 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
606 | struct dentry *parent = dentry->d_parent; | ||
607 | struct qstr *name = &dentry->d_name; | ||
416 | unsigned int len = name->len; | 608 | unsigned int len = name->len; |
417 | unsigned int hash = name->hash; | 609 | unsigned int hash = name->hash; |
418 | const unsigned char *str = name->name; | 610 | const unsigned char *str = name->name; |
@@ -423,23 +615,23 @@ static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct | |||
423 | head = &sbi->expiring_list; | 615 | head = &sbi->expiring_list; |
424 | list_for_each(p, head) { | 616 | list_for_each(p, head) { |
425 | struct autofs_info *ino; | 617 | struct autofs_info *ino; |
426 | struct dentry *dentry; | 618 | struct dentry *expiring; |
427 | struct qstr *qstr; | 619 | struct qstr *qstr; |
428 | 620 | ||
429 | ino = list_entry(p, struct autofs_info, expiring); | 621 | ino = list_entry(p, struct autofs_info, expiring); |
430 | dentry = ino->dentry; | 622 | expiring = ino->dentry; |
431 | 623 | ||
432 | spin_lock(&dentry->d_lock); | 624 | spin_lock(&expiring->d_lock); |
433 | 625 | ||
434 | /* Bad luck, we've already been dentry_iput */ | 626 | /* Bad luck, we've already been dentry_iput */ |
435 | if (!dentry->d_inode) | 627 | if (!expiring->d_inode) |
436 | goto next; | 628 | goto next; |
437 | 629 | ||
438 | qstr = &dentry->d_name; | 630 | qstr = &expiring->d_name; |
439 | 631 | ||
440 | if (dentry->d_name.hash != hash) | 632 | if (expiring->d_name.hash != hash) |
441 | goto next; | 633 | goto next; |
442 | if (dentry->d_parent != parent) | 634 | if (expiring->d_parent != parent) |
443 | goto next; | 635 | goto next; |
444 | 636 | ||
445 | if (qstr->len != len) | 637 | if (qstr->len != len) |
@@ -447,15 +639,13 @@ static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct | |||
447 | if (memcmp(qstr->name, str, len)) | 639 | if (memcmp(qstr->name, str, len)) |
448 | goto next; | 640 | goto next; |
449 | 641 | ||
450 | if (d_unhashed(dentry)) { | 642 | dget(expiring); |
451 | dget(dentry); | 643 | spin_unlock(&expiring->d_lock); |
452 | spin_unlock(&dentry->d_lock); | 644 | spin_unlock(&sbi->lookup_lock); |
453 | spin_unlock(&sbi->lookup_lock); | 645 | spin_unlock(&dcache_lock); |
454 | spin_unlock(&dcache_lock); | 646 | return expiring; |
455 | return dentry; | ||
456 | } | ||
457 | next: | 647 | next: |
458 | spin_unlock(&dentry->d_lock); | 648 | spin_unlock(&expiring->d_lock); |
459 | } | 649 | } |
460 | spin_unlock(&sbi->lookup_lock); | 650 | spin_unlock(&sbi->lookup_lock); |
461 | spin_unlock(&dcache_lock); | 651 | spin_unlock(&dcache_lock); |
@@ -463,13 +653,56 @@ next: | |||
463 | return NULL; | 653 | return NULL; |
464 | } | 654 | } |
465 | 655 | ||
656 | static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi, | ||
657 | struct dentry *dentry, int oz_mode) | ||
658 | { | ||
659 | struct autofs_info *ino; | ||
660 | |||
661 | /* | ||
662 | * Mark the dentry incomplete but don't hash it. We do this | ||
663 | * to serialize our inode creation operations (symlink and | ||
664 | * mkdir) which prevents deadlock during the callback to | ||
665 | * the daemon. Subsequent user space lookups for the same | ||
666 | * dentry are placed on the wait queue while the daemon | ||
667 | * itself is allowed passage unresticted so the create | ||
668 | * operation itself can then hash the dentry. Finally, | ||
669 | * we check for the hashed dentry and return the newly | ||
670 | * hashed dentry. | ||
671 | */ | ||
672 | dentry->d_op = &autofs4_root_dentry_operations; | ||
673 | |||
674 | /* | ||
675 | * And we need to ensure that the same dentry is used for | ||
676 | * all following lookup calls until it is hashed so that | ||
677 | * the dentry flags are persistent throughout the request. | ||
678 | */ | ||
679 | ino = autofs4_init_ino(NULL, sbi, 0555); | ||
680 | if (!ino) | ||
681 | return ERR_PTR(-ENOMEM); | ||
682 | |||
683 | dentry->d_fsdata = ino; | ||
684 | ino->dentry = dentry; | ||
685 | |||
686 | /* | ||
687 | * Only set the mount pending flag for new dentrys not created | ||
688 | * by the daemon. | ||
689 | */ | ||
690 | if (!oz_mode) | ||
691 | ino->flags |= AUTOFS_INF_PENDING; | ||
692 | |||
693 | d_instantiate(dentry, NULL); | ||
694 | |||
695 | return ino; | ||
696 | } | ||
697 | |||
466 | /* Lookups in the root directory */ | 698 | /* Lookups in the root directory */ |
467 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 699 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
468 | { | 700 | { |
469 | struct autofs_sb_info *sbi; | 701 | struct autofs_sb_info *sbi; |
470 | struct autofs_info *ino; | 702 | struct autofs_info *ino; |
471 | struct dentry *expiring, *unhashed; | 703 | struct dentry *expiring, *active; |
472 | int oz_mode; | 704 | int oz_mode; |
705 | int status = 0; | ||
473 | 706 | ||
474 | DPRINTK("name = %.*s", | 707 | DPRINTK("name = %.*s", |
475 | dentry->d_name.len, dentry->d_name.name); | 708 | dentry->d_name.len, dentry->d_name.name); |
@@ -484,123 +717,100 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
484 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", | 717 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", |
485 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); | 718 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); |
486 | 719 | ||
487 | unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); | 720 | spin_lock(&sbi->fs_lock); |
488 | if (unhashed) | 721 | active = autofs4_lookup_active(dentry); |
489 | dentry = unhashed; | 722 | if (active) { |
490 | else { | 723 | dentry = active; |
491 | /* | 724 | ino = autofs4_dentry_ino(dentry); |
492 | * Mark the dentry incomplete but don't hash it. We do this | 725 | /* If this came from revalidate, rehash it */ |
493 | * to serialize our inode creation operations (symlink and | 726 | autofs4_revalidate_rehash(dentry); |
494 | * mkdir) which prevents deadlock during the callback to | 727 | spin_unlock(&sbi->fs_lock); |
495 | * the daemon. Subsequent user space lookups for the same | 728 | } else { |
496 | * dentry are placed on the wait queue while the daemon | 729 | spin_unlock(&sbi->fs_lock); |
497 | * itself is allowed passage unresticted so the create | 730 | ino = init_new_dentry(sbi, dentry, oz_mode); |
498 | * operation itself can then hash the dentry. Finally, | 731 | if (IS_ERR(ino)) |
499 | * we check for the hashed dentry and return the newly | 732 | return (struct dentry *) ino; |
500 | * hashed dentry. | ||
501 | */ | ||
502 | dentry->d_op = &autofs4_root_dentry_operations; | ||
503 | |||
504 | /* | ||
505 | * And we need to ensure that the same dentry is used for | ||
506 | * all following lookup calls until it is hashed so that | ||
507 | * the dentry flags are persistent throughout the request. | ||
508 | */ | ||
509 | ino = autofs4_init_ino(NULL, sbi, 0555); | ||
510 | if (!ino) | ||
511 | return ERR_PTR(-ENOMEM); | ||
512 | |||
513 | dentry->d_fsdata = ino; | ||
514 | ino->dentry = dentry; | ||
515 | |||
516 | spin_lock(&sbi->lookup_lock); | ||
517 | list_add(&ino->active, &sbi->active_list); | ||
518 | spin_unlock(&sbi->lookup_lock); | ||
519 | |||
520 | d_instantiate(dentry, NULL); | ||
521 | } | 733 | } |
522 | 734 | ||
735 | autofs4_add_active(dentry); | ||
736 | |||
523 | if (!oz_mode) { | 737 | if (!oz_mode) { |
738 | expiring = autofs4_lookup_expiring(dentry); | ||
524 | mutex_unlock(&dir->i_mutex); | 739 | mutex_unlock(&dir->i_mutex); |
525 | expiring = autofs4_lookup_expiring(sbi, | ||
526 | dentry->d_parent, | ||
527 | &dentry->d_name); | ||
528 | if (expiring) { | 740 | if (expiring) { |
529 | /* | 741 | /* |
530 | * If we are racing with expire the request might not | 742 | * If we are racing with expire the request might not |
531 | * be quite complete but the directory has been removed | 743 | * be quite complete but the directory has been removed |
532 | * so it must have been successful, so just wait for it. | 744 | * so it must have been successful, so just wait for it. |
533 | */ | 745 | */ |
534 | ino = autofs4_dentry_ino(expiring); | ||
535 | autofs4_expire_wait(expiring); | 746 | autofs4_expire_wait(expiring); |
536 | spin_lock(&sbi->lookup_lock); | ||
537 | if (!list_empty(&ino->expiring)) | ||
538 | list_del_init(&ino->expiring); | ||
539 | spin_unlock(&sbi->lookup_lock); | ||
540 | dput(expiring); | 747 | dput(expiring); |
541 | } | 748 | } |
542 | 749 | status = try_to_fill_dentry(dentry); | |
543 | spin_lock(&dentry->d_lock); | ||
544 | dentry->d_flags |= DCACHE_AUTOFS_PENDING; | ||
545 | spin_unlock(&dentry->d_lock); | ||
546 | if (dentry->d_op && dentry->d_op->d_revalidate) | ||
547 | (dentry->d_op->d_revalidate)(dentry, nd); | ||
548 | mutex_lock(&dir->i_mutex); | 750 | mutex_lock(&dir->i_mutex); |
751 | spin_lock(&sbi->fs_lock); | ||
752 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
753 | spin_unlock(&sbi->fs_lock); | ||
549 | } | 754 | } |
550 | 755 | ||
756 | autofs4_del_active(dentry); | ||
757 | |||
551 | /* | 758 | /* |
552 | * If we are still pending, check if we had to handle | 759 | * If we had a mount fail, check if we had to handle |
553 | * a signal. If so we can force a restart.. | 760 | * a signal. If so we can force a restart.. |
554 | */ | 761 | */ |
555 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { | 762 | if (status) { |
556 | /* See if we were interrupted */ | 763 | /* See if we were interrupted */ |
557 | if (signal_pending(current)) { | 764 | if (signal_pending(current)) { |
558 | sigset_t *sigset = ¤t->pending.signal; | 765 | sigset_t *sigset = ¤t->pending.signal; |
559 | if (sigismember (sigset, SIGKILL) || | 766 | if (sigismember (sigset, SIGKILL) || |
560 | sigismember (sigset, SIGQUIT) || | 767 | sigismember (sigset, SIGQUIT) || |
561 | sigismember (sigset, SIGINT)) { | 768 | sigismember (sigset, SIGINT)) { |
562 | if (unhashed) | 769 | if (active) |
563 | dput(unhashed); | 770 | dput(active); |
564 | return ERR_PTR(-ERESTARTNOINTR); | 771 | return ERR_PTR(-ERESTARTNOINTR); |
565 | } | 772 | } |
566 | } | 773 | } |
567 | if (!oz_mode) { | 774 | } |
568 | spin_lock(&dentry->d_lock); | 775 | |
569 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 776 | /* |
570 | spin_unlock(&dentry->d_lock); | 777 | * User space can (and has done in the past) remove and re-create |
778 | * this directory during the callback. This can leave us with an | ||
779 | * unhashed dentry, but a successful mount! So we need to | ||
780 | * perform another cached lookup in case the dentry now exists. | ||
781 | */ | ||
782 | if (!oz_mode && !have_submounts(dentry)) { | ||
783 | struct dentry *new; | ||
784 | new = d_lookup(dentry->d_parent, &dentry->d_name); | ||
785 | if (new) { | ||
786 | if (active) | ||
787 | dput(active); | ||
788 | return new; | ||
789 | } else { | ||
790 | if (!status) | ||
791 | status = -ENOENT; | ||
571 | } | 792 | } |
572 | } | 793 | } |
573 | 794 | ||
574 | /* | 795 | /* |
575 | * If this dentry is unhashed, then we shouldn't honour this | 796 | * If we had a mount failure, return status to user space. |
576 | * lookup. Returning ENOENT here doesn't do the right thing | 797 | * If the mount succeeded and we used a dentry from the active queue |
577 | * for all system calls, but it should be OK for the operations | 798 | * return it. |
578 | * we permit from an autofs. | ||
579 | */ | 799 | */ |
580 | if (!oz_mode && d_unhashed(dentry)) { | 800 | if (status) { |
801 | dentry = ERR_PTR(status); | ||
802 | if (active) | ||
803 | dput(active); | ||
804 | return dentry; | ||
805 | } else { | ||
581 | /* | 806 | /* |
582 | * A user space application can (and has done in the past) | 807 | * Valid successful mount, return active dentry or NULL |
583 | * remove and re-create this directory during the callback. | 808 | * for a new dentry. |
584 | * This can leave us with an unhashed dentry, but a | ||
585 | * successful mount! So we need to perform another | ||
586 | * cached lookup in case the dentry now exists. | ||
587 | */ | 809 | */ |
588 | struct dentry *parent = dentry->d_parent; | 810 | if (active) |
589 | struct dentry *new = d_lookup(parent, &dentry->d_name); | 811 | return active; |
590 | if (new != NULL) | ||
591 | dentry = new; | ||
592 | else | ||
593 | dentry = ERR_PTR(-ENOENT); | ||
594 | |||
595 | if (unhashed) | ||
596 | dput(unhashed); | ||
597 | |||
598 | return dentry; | ||
599 | } | 812 | } |
600 | 813 | ||
601 | if (unhashed) | ||
602 | return unhashed; | ||
603 | |||
604 | return NULL; | 814 | return NULL; |
605 | } | 815 | } |
606 | 816 | ||
@@ -624,11 +834,6 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
624 | if (!ino) | 834 | if (!ino) |
625 | return -ENOMEM; | 835 | return -ENOMEM; |
626 | 836 | ||
627 | spin_lock(&sbi->lookup_lock); | ||
628 | if (!list_empty(&ino->active)) | ||
629 | list_del_init(&ino->active); | ||
630 | spin_unlock(&sbi->lookup_lock); | ||
631 | |||
632 | ino->size = strlen(symname); | 837 | ino->size = strlen(symname); |
633 | cp = kmalloc(ino->size + 1, GFP_KERNEL); | 838 | cp = kmalloc(ino->size + 1, GFP_KERNEL); |
634 | if (!cp) { | 839 | if (!cp) { |
@@ -705,10 +910,6 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
705 | dir->i_mtime = CURRENT_TIME; | 910 | dir->i_mtime = CURRENT_TIME; |
706 | 911 | ||
707 | spin_lock(&dcache_lock); | 912 | spin_lock(&dcache_lock); |
708 | spin_lock(&sbi->lookup_lock); | ||
709 | if (list_empty(&ino->expiring)) | ||
710 | list_add(&ino->expiring, &sbi->expiring_list); | ||
711 | spin_unlock(&sbi->lookup_lock); | ||
712 | spin_lock(&dentry->d_lock); | 913 | spin_lock(&dentry->d_lock); |
713 | __d_drop(dentry); | 914 | __d_drop(dentry); |
714 | spin_unlock(&dentry->d_lock); | 915 | spin_unlock(&dentry->d_lock); |
@@ -734,10 +935,6 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
734 | spin_unlock(&dcache_lock); | 935 | spin_unlock(&dcache_lock); |
735 | return -ENOTEMPTY; | 936 | return -ENOTEMPTY; |
736 | } | 937 | } |
737 | spin_lock(&sbi->lookup_lock); | ||
738 | if (list_empty(&ino->expiring)) | ||
739 | list_add(&ino->expiring, &sbi->expiring_list); | ||
740 | spin_unlock(&sbi->lookup_lock); | ||
741 | spin_lock(&dentry->d_lock); | 938 | spin_lock(&dentry->d_lock); |
742 | __d_drop(dentry); | 939 | __d_drop(dentry); |
743 | spin_unlock(&dentry->d_lock); | 940 | spin_unlock(&dentry->d_lock); |
@@ -775,11 +972,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
775 | if (!ino) | 972 | if (!ino) |
776 | return -ENOMEM; | 973 | return -ENOMEM; |
777 | 974 | ||
778 | spin_lock(&sbi->lookup_lock); | ||
779 | if (!list_empty(&ino->active)) | ||
780 | list_del_init(&ino->active); | ||
781 | spin_unlock(&sbi->lookup_lock); | ||
782 | |||
783 | inode = autofs4_get_inode(dir->i_sb, ino); | 975 | inode = autofs4_get_inode(dir->i_sb, ino); |
784 | if (!inode) { | 976 | if (!inode) { |
785 | if (!dentry->d_fsdata) | 977 | if (!dentry->d_fsdata) |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d15ea1790bfb..97b6e9efeb7f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -44,7 +44,7 @@ static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, | |||
44 | * If we don't support core dumping, then supply a NULL so we | 44 | * If we don't support core dumping, then supply a NULL so we |
45 | * don't even try. | 45 | * don't even try. |
46 | */ | 46 | */ |
47 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 47 | #ifdef CONFIG_ELF_CORE |
48 | static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); | 48 | static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); |
49 | #else | 49 | #else |
50 | #define elf_core_dump NULL | 50 | #define elf_core_dump NULL |
@@ -1101,12 +1101,7 @@ out: | |||
1101 | return error; | 1101 | return error; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | /* | 1104 | #ifdef CONFIG_ELF_CORE |
1105 | * Note that some platforms still use traditional core dumps and not | ||
1106 | * the ELF core dump. Each platform can select it as appropriate. | ||
1107 | */ | ||
1108 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | ||
1109 | |||
1110 | /* | 1105 | /* |
1111 | * ELF core dumper | 1106 | * ELF core dumper |
1112 | * | 1107 | * |
@@ -2063,7 +2058,7 @@ out: | |||
2063 | return has_dumped; | 2058 | return has_dumped; |
2064 | } | 2059 | } |
2065 | 2060 | ||
2066 | #endif /* USE_ELF_CORE_DUMP */ | 2061 | #endif /* CONFIG_ELF_CORE */ |
2067 | 2062 | ||
2068 | static int __init init_elf_binfmt(void) | 2063 | static int __init init_elf_binfmt(void) |
2069 | { | 2064 | { |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 79d2b1aa389f..7b055385db8e 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -75,14 +75,14 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *, | |||
75 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, | 75 | static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, |
76 | struct file *, struct mm_struct *); | 76 | struct file *, struct mm_struct *); |
77 | 77 | ||
78 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 78 | #ifdef CONFIG_ELF_CORE |
79 | static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit); | 79 | static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit); |
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | static struct linux_binfmt elf_fdpic_format = { | 82 | static struct linux_binfmt elf_fdpic_format = { |
83 | .module = THIS_MODULE, | 83 | .module = THIS_MODULE, |
84 | .load_binary = load_elf_fdpic_binary, | 84 | .load_binary = load_elf_fdpic_binary, |
85 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 85 | #ifdef CONFIG_ELF_CORE |
86 | .core_dump = elf_fdpic_core_dump, | 86 | .core_dump = elf_fdpic_core_dump, |
87 | #endif | 87 | #endif |
88 | .min_coredump = ELF_EXEC_PAGESIZE, | 88 | .min_coredump = ELF_EXEC_PAGESIZE, |
@@ -1201,7 +1201,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, | |||
1201 | * | 1201 | * |
1202 | * Modelled on fs/binfmt_elf.c core dumper | 1202 | * Modelled on fs/binfmt_elf.c core dumper |
1203 | */ | 1203 | */ |
1204 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 1204 | #ifdef CONFIG_ELF_CORE |
1205 | 1205 | ||
1206 | /* | 1206 | /* |
1207 | * These are the only things you should do on a core-file: use only these | 1207 | * These are the only things you should do on a core-file: use only these |
@@ -1826,4 +1826,4 @@ cleanup: | |||
1826 | #undef NUM_NOTES | 1826 | #undef NUM_NOTES |
1827 | } | 1827 | } |
1828 | 1828 | ||
1829 | #endif /* USE_ELF_CORE_DUMP */ | 1829 | #endif /* CONFIG_ELF_CORE */ |
diff --git a/fs/direct-io.c b/fs/direct-io.c index b912270942fa..4012885d027f 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -53,13 +53,6 @@ | |||
53 | * | 53 | * |
54 | * If blkfactor is zero then the user's request was aligned to the filesystem's | 54 | * If blkfactor is zero then the user's request was aligned to the filesystem's |
55 | * blocksize. | 55 | * blocksize. |
56 | * | ||
57 | * lock_type is DIO_LOCKING for regular files on direct-IO-naive filesystems. | ||
58 | * This determines whether we need to do the fancy locking which prevents | ||
59 | * direct-IO from being able to read uninitialised disk blocks. If its zero | ||
60 | * (blockdev) this locking is not done, and if it is DIO_OWN_LOCKING i_mutex is | ||
61 | * not held for the entire direct write (taken briefly, initially, during a | ||
62 | * direct read though, but its never held for the duration of a direct-IO). | ||
63 | */ | 56 | */ |
64 | 57 | ||
65 | struct dio { | 58 | struct dio { |
@@ -68,7 +61,7 @@ struct dio { | |||
68 | struct inode *inode; | 61 | struct inode *inode; |
69 | int rw; | 62 | int rw; |
70 | loff_t i_size; /* i_size when submitted */ | 63 | loff_t i_size; /* i_size when submitted */ |
71 | int lock_type; /* doesn't change */ | 64 | int flags; /* doesn't change */ |
72 | unsigned blkbits; /* doesn't change */ | 65 | unsigned blkbits; /* doesn't change */ |
73 | unsigned blkfactor; /* When we're using an alignment which | 66 | unsigned blkfactor; /* When we're using an alignment which |
74 | is finer than the filesystem's soft | 67 | is finer than the filesystem's soft |
@@ -104,6 +97,18 @@ struct dio { | |||
104 | unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ | 97 | unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ |
105 | sector_t cur_page_block; /* Where it starts */ | 98 | sector_t cur_page_block; /* Where it starts */ |
106 | 99 | ||
100 | /* BIO completion state */ | ||
101 | spinlock_t bio_lock; /* protects BIO fields below */ | ||
102 | unsigned long refcount; /* direct_io_worker() and bios */ | ||
103 | struct bio *bio_list; /* singly linked via bi_private */ | ||
104 | struct task_struct *waiter; /* waiting task (NULL if none) */ | ||
105 | |||
106 | /* AIO related stuff */ | ||
107 | struct kiocb *iocb; /* kiocb */ | ||
108 | int is_async; /* is IO async ? */ | ||
109 | int io_error; /* IO error in completion path */ | ||
110 | ssize_t result; /* IO result */ | ||
111 | |||
107 | /* | 112 | /* |
108 | * Page fetching state. These variables belong to dio_refill_pages(). | 113 | * Page fetching state. These variables belong to dio_refill_pages(). |
109 | */ | 114 | */ |
@@ -115,22 +120,16 @@ struct dio { | |||
115 | * Page queue. These variables belong to dio_refill_pages() and | 120 | * Page queue. These variables belong to dio_refill_pages() and |
116 | * dio_get_page(). | 121 | * dio_get_page(). |
117 | */ | 122 | */ |
118 | struct page *pages[DIO_PAGES]; /* page buffer */ | ||
119 | unsigned head; /* next page to process */ | 123 | unsigned head; /* next page to process */ |
120 | unsigned tail; /* last valid page + 1 */ | 124 | unsigned tail; /* last valid page + 1 */ |
121 | int page_errors; /* errno from get_user_pages() */ | 125 | int page_errors; /* errno from get_user_pages() */ |
122 | 126 | ||
123 | /* BIO completion state */ | 127 | /* |
124 | spinlock_t bio_lock; /* protects BIO fields below */ | 128 | * pages[] (and any fields placed after it) are not zeroed out at |
125 | unsigned long refcount; /* direct_io_worker() and bios */ | 129 | * allocation time. Don't add new fields after pages[] unless you |
126 | struct bio *bio_list; /* singly linked via bi_private */ | 130 | * wish that they not be zeroed. |
127 | struct task_struct *waiter; /* waiting task (NULL if none) */ | 131 | */ |
128 | 132 | struct page *pages[DIO_PAGES]; /* page buffer */ | |
129 | /* AIO related stuff */ | ||
130 | struct kiocb *iocb; /* kiocb */ | ||
131 | int is_async; /* is IO async ? */ | ||
132 | int io_error; /* IO error in completion path */ | ||
133 | ssize_t result; /* IO result */ | ||
134 | }; | 133 | }; |
135 | 134 | ||
136 | /* | 135 | /* |
@@ -240,7 +239,8 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) | |||
240 | if (dio->end_io && dio->result) | 239 | if (dio->end_io && dio->result) |
241 | dio->end_io(dio->iocb, offset, transferred, | 240 | dio->end_io(dio->iocb, offset, transferred, |
242 | dio->map_bh.b_private); | 241 | dio->map_bh.b_private); |
243 | if (dio->lock_type == DIO_LOCKING) | 242 | |
243 | if (dio->flags & DIO_LOCKING) | ||
244 | /* lockdep: non-owner release */ | 244 | /* lockdep: non-owner release */ |
245 | up_read_non_owner(&dio->inode->i_alloc_sem); | 245 | up_read_non_owner(&dio->inode->i_alloc_sem); |
246 | 246 | ||
@@ -515,21 +515,24 @@ static int get_more_blocks(struct dio *dio) | |||
515 | map_bh->b_state = 0; | 515 | map_bh->b_state = 0; |
516 | map_bh->b_size = fs_count << dio->inode->i_blkbits; | 516 | map_bh->b_size = fs_count << dio->inode->i_blkbits; |
517 | 517 | ||
518 | /* | ||
519 | * For writes inside i_size on a DIO_SKIP_HOLES filesystem we | ||
520 | * forbid block creations: only overwrites are permitted. | ||
521 | * We will return early to the caller once we see an | ||
522 | * unmapped buffer head returned, and the caller will fall | ||
523 | * back to buffered I/O. | ||
524 | * | ||
525 | * Otherwise the decision is left to the get_blocks method, | ||
526 | * which may decide to handle it or also return an unmapped | ||
527 | * buffer head. | ||
528 | */ | ||
518 | create = dio->rw & WRITE; | 529 | create = dio->rw & WRITE; |
519 | if (dio->lock_type == DIO_LOCKING) { | 530 | if (dio->flags & DIO_SKIP_HOLES) { |
520 | if (dio->block_in_file < (i_size_read(dio->inode) >> | 531 | if (dio->block_in_file < (i_size_read(dio->inode) >> |
521 | dio->blkbits)) | 532 | dio->blkbits)) |
522 | create = 0; | 533 | create = 0; |
523 | } else if (dio->lock_type == DIO_NO_LOCKING) { | ||
524 | create = 0; | ||
525 | } | 534 | } |
526 | 535 | ||
527 | /* | ||
528 | * For writes inside i_size we forbid block creations: only | ||
529 | * overwrites are permitted. We fall back to buffered writes | ||
530 | * at a higher level for inside-i_size block-instantiating | ||
531 | * writes. | ||
532 | */ | ||
533 | ret = (*dio->get_block)(dio->inode, fs_startblk, | 536 | ret = (*dio->get_block)(dio->inode, fs_startblk, |
534 | map_bh, create); | 537 | map_bh, create); |
535 | } | 538 | } |
@@ -1039,7 +1042,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
1039 | * we can let i_mutex go now that its achieved its purpose | 1042 | * we can let i_mutex go now that its achieved its purpose |
1040 | * of protecting us from looking up uninitialized blocks. | 1043 | * of protecting us from looking up uninitialized blocks. |
1041 | */ | 1044 | */ |
1042 | if ((rw == READ) && (dio->lock_type == DIO_LOCKING)) | 1045 | if (rw == READ && (dio->flags & DIO_LOCKING)) |
1043 | mutex_unlock(&dio->inode->i_mutex); | 1046 | mutex_unlock(&dio->inode->i_mutex); |
1044 | 1047 | ||
1045 | /* | 1048 | /* |
@@ -1086,30 +1089,28 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
1086 | 1089 | ||
1087 | /* | 1090 | /* |
1088 | * This is a library function for use by filesystem drivers. | 1091 | * This is a library function for use by filesystem drivers. |
1089 | * The locking rules are governed by the dio_lock_type parameter. | ||
1090 | * | 1092 | * |
1091 | * DIO_NO_LOCKING (no locking, for raw block device access) | 1093 | * The locking rules are governed by the flags parameter: |
1092 | * For writes, i_mutex is not held on entry; it is never taken. | 1094 | * - if the flags value contains DIO_LOCKING we use a fancy locking |
1095 | * scheme for dumb filesystems. | ||
1096 | * For writes this function is called under i_mutex and returns with | ||
1097 | * i_mutex held, for reads, i_mutex is not held on entry, but it is | ||
1098 | * taken and dropped again before returning. | ||
1099 | * For reads and writes i_alloc_sem is taken in shared mode and released | ||
1100 | * on I/O completion (which may happen asynchronously after returning to | ||
1101 | * the caller). | ||
1093 | * | 1102 | * |
1094 | * DIO_LOCKING (simple locking for regular files) | 1103 | * - if the flags value does NOT contain DIO_LOCKING we don't use any |
1095 | * For writes we are called under i_mutex and return with i_mutex held, even | 1104 | * internal locking but rather rely on the filesystem to synchronize |
1096 | * though it is internally dropped. | 1105 | * direct I/O reads/writes versus each other and truncate. |
1097 | * For reads, i_mutex is not held on entry, but it is taken and dropped before | 1106 | * For reads and writes both i_mutex and i_alloc_sem are not held on |
1098 | * returning. | 1107 | * entry and are never taken. |
1099 | * | ||
1100 | * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of | ||
1101 | * uninitialised data, allowing parallel direct readers and writers) | ||
1102 | * For writes we are called without i_mutex, return without it, never touch it. | ||
1103 | * For reads we are called under i_mutex and return with i_mutex held, even | ||
1104 | * though it may be internally dropped. | ||
1105 | * | ||
1106 | * Additional i_alloc_sem locking requirements described inline below. | ||
1107 | */ | 1108 | */ |
1108 | ssize_t | 1109 | ssize_t |
1109 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | 1110 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, |
1110 | struct block_device *bdev, const struct iovec *iov, loff_t offset, | 1111 | struct block_device *bdev, const struct iovec *iov, loff_t offset, |
1111 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, | 1112 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, |
1112 | int dio_lock_type) | 1113 | int flags) |
1113 | { | 1114 | { |
1114 | int seg; | 1115 | int seg; |
1115 | size_t size; | 1116 | size_t size; |
@@ -1120,8 +1121,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1120 | ssize_t retval = -EINVAL; | 1121 | ssize_t retval = -EINVAL; |
1121 | loff_t end = offset; | 1122 | loff_t end = offset; |
1122 | struct dio *dio; | 1123 | struct dio *dio; |
1123 | int release_i_mutex = 0; | ||
1124 | int acquire_i_mutex = 0; | ||
1125 | 1124 | ||
1126 | if (rw & WRITE) | 1125 | if (rw & WRITE) |
1127 | rw = WRITE_ODIRECT_PLUG; | 1126 | rw = WRITE_ODIRECT_PLUG; |
@@ -1151,48 +1150,41 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1151 | } | 1150 | } |
1152 | } | 1151 | } |
1153 | 1152 | ||
1154 | dio = kzalloc(sizeof(*dio), GFP_KERNEL); | 1153 | dio = kmalloc(sizeof(*dio), GFP_KERNEL); |
1155 | retval = -ENOMEM; | 1154 | retval = -ENOMEM; |
1156 | if (!dio) | 1155 | if (!dio) |
1157 | goto out; | 1156 | goto out; |
1158 | |||
1159 | /* | 1157 | /* |
1160 | * For block device access DIO_NO_LOCKING is used, | 1158 | * Believe it or not, zeroing out the page array caused a .5% |
1161 | * neither readers nor writers do any locking at all | 1159 | * performance regression in a database benchmark. So, we take |
1162 | * For regular files using DIO_LOCKING, | 1160 | * care to only zero out what's needed. |
1163 | * readers need to grab i_mutex and i_alloc_sem | ||
1164 | * writers need to grab i_alloc_sem only (i_mutex is already held) | ||
1165 | * For regular files using DIO_OWN_LOCKING, | ||
1166 | * neither readers nor writers take any locks here | ||
1167 | */ | 1161 | */ |
1168 | dio->lock_type = dio_lock_type; | 1162 | memset(dio, 0, offsetof(struct dio, pages)); |
1169 | if (dio_lock_type != DIO_NO_LOCKING) { | 1163 | |
1164 | dio->flags = flags; | ||
1165 | if (dio->flags & DIO_LOCKING) { | ||
1170 | /* watch out for a 0 len io from a tricksy fs */ | 1166 | /* watch out for a 0 len io from a tricksy fs */ |
1171 | if (rw == READ && end > offset) { | 1167 | if (rw == READ && end > offset) { |
1172 | struct address_space *mapping; | 1168 | struct address_space *mapping = |
1169 | iocb->ki_filp->f_mapping; | ||
1173 | 1170 | ||
1174 | mapping = iocb->ki_filp->f_mapping; | 1171 | /* will be released by direct_io_worker */ |
1175 | if (dio_lock_type != DIO_OWN_LOCKING) { | 1172 | mutex_lock(&inode->i_mutex); |
1176 | mutex_lock(&inode->i_mutex); | ||
1177 | release_i_mutex = 1; | ||
1178 | } | ||
1179 | 1173 | ||
1180 | retval = filemap_write_and_wait_range(mapping, offset, | 1174 | retval = filemap_write_and_wait_range(mapping, offset, |
1181 | end - 1); | 1175 | end - 1); |
1182 | if (retval) { | 1176 | if (retval) { |
1177 | mutex_unlock(&inode->i_mutex); | ||
1183 | kfree(dio); | 1178 | kfree(dio); |
1184 | goto out; | 1179 | goto out; |
1185 | } | 1180 | } |
1186 | |||
1187 | if (dio_lock_type == DIO_OWN_LOCKING) { | ||
1188 | mutex_unlock(&inode->i_mutex); | ||
1189 | acquire_i_mutex = 1; | ||
1190 | } | ||
1191 | } | 1181 | } |
1192 | 1182 | ||
1193 | if (dio_lock_type == DIO_LOCKING) | 1183 | /* |
1194 | /* lockdep: not the owner will release it */ | 1184 | * Will be released at I/O completion, possibly in a |
1195 | down_read_non_owner(&inode->i_alloc_sem); | 1185 | * different thread. |
1186 | */ | ||
1187 | down_read_non_owner(&inode->i_alloc_sem); | ||
1196 | } | 1188 | } |
1197 | 1189 | ||
1198 | /* | 1190 | /* |
@@ -1210,24 +1202,19 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1210 | /* | 1202 | /* |
1211 | * In case of error extending write may have instantiated a few | 1203 | * In case of error extending write may have instantiated a few |
1212 | * blocks outside i_size. Trim these off again for DIO_LOCKING. | 1204 | * blocks outside i_size. Trim these off again for DIO_LOCKING. |
1213 | * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this by | 1205 | * |
1214 | * it's own meaner. | 1206 | * NOTE: filesystems with their own locking have to handle this |
1207 | * on their own. | ||
1215 | */ | 1208 | */ |
1216 | if (unlikely(retval < 0 && (rw & WRITE))) { | 1209 | if (dio->flags & DIO_LOCKING) { |
1217 | loff_t isize = i_size_read(inode); | 1210 | if (unlikely((rw & WRITE) && retval < 0)) { |
1218 | 1211 | loff_t isize = i_size_read(inode); | |
1219 | if (end > isize && dio_lock_type == DIO_LOCKING) | 1212 | if (end > isize) |
1220 | vmtruncate(inode, isize); | 1213 | vmtruncate(inode, isize); |
1214 | } | ||
1221 | } | 1215 | } |
1222 | 1216 | ||
1223 | if (rw == READ && dio_lock_type == DIO_LOCKING) | ||
1224 | release_i_mutex = 0; | ||
1225 | |||
1226 | out: | 1217 | out: |
1227 | if (release_i_mutex) | ||
1228 | mutex_unlock(&inode->i_mutex); | ||
1229 | else if (acquire_i_mutex) | ||
1230 | mutex_lock(&inode->i_mutex); | ||
1231 | return retval; | 1218 | return retval; |
1232 | } | 1219 | } |
1233 | EXPORT_SYMBOL(__blockdev_direct_IO); | 1220 | EXPORT_SYMBOL(__blockdev_direct_IO); |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index fc2bd05d3559..7516957273ed 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
@@ -721,5 +721,5 @@ const struct file_operations ext2_dir_operations = { | |||
721 | #ifdef CONFIG_COMPAT | 721 | #ifdef CONFIG_COMPAT |
722 | .compat_ioctl = ext2_compat_ioctl, | 722 | .compat_ioctl = ext2_compat_ioctl, |
723 | #endif | 723 | #endif |
724 | .fsync = simple_fsync, | 724 | .fsync = ext2_fsync, |
725 | }; | 725 | }; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index da318b0fa637..061914add3cf 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -155,6 +155,7 @@ extern void ext2_write_super (struct super_block *); | |||
155 | extern const struct file_operations ext2_dir_operations; | 155 | extern const struct file_operations ext2_dir_operations; |
156 | 156 | ||
157 | /* file.c */ | 157 | /* file.c */ |
158 | extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync); | ||
158 | extern const struct inode_operations ext2_file_inode_operations; | 159 | extern const struct inode_operations ext2_file_inode_operations; |
159 | extern const struct file_operations ext2_file_operations; | 160 | extern const struct file_operations ext2_file_operations; |
160 | extern const struct file_operations ext2_xip_file_operations; | 161 | extern const struct file_operations ext2_xip_file_operations; |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index a2f3afd1a1c1..586e3589d4c2 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/time.h> | 21 | #include <linux/time.h> |
22 | #include <linux/pagemap.h> | ||
22 | #include "ext2.h" | 23 | #include "ext2.h" |
23 | #include "xattr.h" | 24 | #include "xattr.h" |
24 | #include "acl.h" | 25 | #include "acl.h" |
@@ -38,6 +39,22 @@ static int ext2_release_file (struct inode * inode, struct file * filp) | |||
38 | return 0; | 39 | return 0; |
39 | } | 40 | } |
40 | 41 | ||
42 | int ext2_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
43 | { | ||
44 | int ret; | ||
45 | struct super_block *sb = dentry->d_inode->i_sb; | ||
46 | struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; | ||
47 | |||
48 | ret = simple_fsync(file, dentry, datasync); | ||
49 | if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { | ||
50 | /* We don't really know where the IO error happened... */ | ||
51 | ext2_error(sb, __func__, | ||
52 | "detected IO error when writing metadata buffers"); | ||
53 | ret = -EIO; | ||
54 | } | ||
55 | return ret; | ||
56 | } | ||
57 | |||
41 | /* | 58 | /* |
42 | * We have mostly NULL's here: the current defaults are ok for | 59 | * We have mostly NULL's here: the current defaults are ok for |
43 | * the ext2 filesystem. | 60 | * the ext2 filesystem. |
@@ -55,7 +72,7 @@ const struct file_operations ext2_file_operations = { | |||
55 | .mmap = generic_file_mmap, | 72 | .mmap = generic_file_mmap, |
56 | .open = generic_file_open, | 73 | .open = generic_file_open, |
57 | .release = ext2_release_file, | 74 | .release = ext2_release_file, |
58 | .fsync = simple_fsync, | 75 | .fsync = ext2_fsync, |
59 | .splice_read = generic_file_splice_read, | 76 | .splice_read = generic_file_splice_read, |
60 | .splice_write = generic_file_splice_write, | 77 | .splice_write = generic_file_splice_write, |
61 | }; | 78 | }; |
@@ -72,7 +89,7 @@ const struct file_operations ext2_xip_file_operations = { | |||
72 | .mmap = xip_file_mmap, | 89 | .mmap = xip_file_mmap, |
73 | .open = generic_file_open, | 90 | .open = generic_file_open, |
74 | .release = ext2_release_file, | 91 | .release = ext2_release_file, |
75 | .fsync = simple_fsync, | 92 | .fsync = ext2_fsync, |
76 | }; | 93 | }; |
77 | #endif | 94 | #endif |
78 | 95 | ||
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 1388802b7803..f9cb54a585ce 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -1105,9 +1105,30 @@ failed_sbi: | |||
1105 | return ret; | 1105 | return ret; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static void ext2_clear_super_error(struct super_block *sb) | ||
1109 | { | ||
1110 | struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; | ||
1111 | |||
1112 | if (buffer_write_io_error(sbh)) { | ||
1113 | /* | ||
1114 | * Oh, dear. A previous attempt to write the | ||
1115 | * superblock failed. This could happen because the | ||
1116 | * USB device was yanked out. Or it could happen to | ||
1117 | * be a transient write error and maybe the block will | ||
1118 | * be remapped. Nothing we can do but to retry the | ||
1119 | * write and hope for the best. | ||
1120 | */ | ||
1121 | printk(KERN_ERR "EXT2-fs: %s previous I/O error to " | ||
1122 | "superblock detected", sb->s_id); | ||
1123 | clear_buffer_write_io_error(sbh); | ||
1124 | set_buffer_uptodate(sbh); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1108 | static void ext2_commit_super (struct super_block * sb, | 1128 | static void ext2_commit_super (struct super_block * sb, |
1109 | struct ext2_super_block * es) | 1129 | struct ext2_super_block * es) |
1110 | { | 1130 | { |
1131 | ext2_clear_super_error(sb); | ||
1111 | es->s_wtime = cpu_to_le32(get_seconds()); | 1132 | es->s_wtime = cpu_to_le32(get_seconds()); |
1112 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | 1133 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
1113 | sb->s_dirt = 0; | 1134 | sb->s_dirt = 0; |
@@ -1115,6 +1136,7 @@ static void ext2_commit_super (struct super_block * sb, | |||
1115 | 1136 | ||
1116 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) | 1137 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) |
1117 | { | 1138 | { |
1139 | ext2_clear_super_error(sb); | ||
1118 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); | 1140 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); |
1119 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); | 1141 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); |
1120 | es->s_wtime = cpu_to_le32(get_seconds()); | 1142 | es->s_wtime = cpu_to_le32(get_seconds()); |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 0f55f5cb732f..d3da05f26465 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | #include <linux/time.h> | ||
12 | #include "fat.h" | 13 | #include "fat.h" |
13 | 14 | ||
14 | /* | 15 | /* |
@@ -157,10 +158,6 @@ extern struct timezone sys_tz; | |||
157 | #define SECS_PER_MIN 60 | 158 | #define SECS_PER_MIN 60 |
158 | #define SECS_PER_HOUR (60 * 60) | 159 | #define SECS_PER_HOUR (60 * 60) |
159 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) | 160 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) |
160 | #define UNIX_SECS_1980 315532800L | ||
161 | #if BITS_PER_LONG == 64 | ||
162 | #define UNIX_SECS_2108 4354819200L | ||
163 | #endif | ||
164 | /* days between 1.1.70 and 1.1.80 (2 leap days) */ | 161 | /* days between 1.1.70 and 1.1.80 (2 leap days) */ |
165 | #define DAYS_DELTA (365 * 10 + 2) | 162 | #define DAYS_DELTA (365 * 10 + 2) |
166 | /* 120 (2100 - 1980) isn't leap year */ | 163 | /* 120 (2100 - 1980) isn't leap year */ |
@@ -213,58 +210,35 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, | |||
213 | void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, | 210 | void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, |
214 | __le16 *time, __le16 *date, u8 *time_cs) | 211 | __le16 *time, __le16 *date, u8 *time_cs) |
215 | { | 212 | { |
216 | time_t second = ts->tv_sec; | 213 | struct tm tm; |
217 | time_t day, leap_day, month, year; | 214 | time_to_tm(ts->tv_sec, sbi->options.tz_utc ? 0 : |
215 | -sys_tz.tz_minuteswest * 60, &tm); | ||
218 | 216 | ||
219 | if (!sbi->options.tz_utc) | 217 | /* FAT can only support year between 1980 to 2107 */ |
220 | second -= sys_tz.tz_minuteswest * SECS_PER_MIN; | 218 | if (tm.tm_year < 1980 - 1900) { |
221 | |||
222 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ | ||
223 | if (second < UNIX_SECS_1980) { | ||
224 | *time = 0; | 219 | *time = 0; |
225 | *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); | 220 | *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); |
226 | if (time_cs) | 221 | if (time_cs) |
227 | *time_cs = 0; | 222 | *time_cs = 0; |
228 | return; | 223 | return; |
229 | } | 224 | } |
230 | #if BITS_PER_LONG == 64 | 225 | if (tm.tm_year > 2107 - 1900) { |
231 | if (second >= UNIX_SECS_2108) { | ||
232 | *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); | 226 | *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); |
233 | *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); | 227 | *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); |
234 | if (time_cs) | 228 | if (time_cs) |
235 | *time_cs = 199; | 229 | *time_cs = 199; |
236 | return; | 230 | return; |
237 | } | 231 | } |
238 | #endif | ||
239 | 232 | ||
240 | day = second / SECS_PER_DAY - DAYS_DELTA; | 233 | /* from 1900 -> from 1980 */ |
241 | year = day / 365; | 234 | tm.tm_year -= 80; |
242 | leap_day = (year + 3) / 4; | 235 | /* 0~11 -> 1~12 */ |
243 | if (year > YEAR_2100) /* 2100 isn't leap year */ | 236 | tm.tm_mon++; |
244 | leap_day--; | 237 | /* 0~59 -> 0~29(2sec counts) */ |
245 | if (year * 365 + leap_day > day) | 238 | tm.tm_sec >>= 1; |
246 | year--; | ||
247 | leap_day = (year + 3) / 4; | ||
248 | if (year > YEAR_2100) /* 2100 isn't leap year */ | ||
249 | leap_day--; | ||
250 | day -= year * 365 + leap_day; | ||
251 | |||
252 | if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { | ||
253 | month = 2; | ||
254 | } else { | ||
255 | if (IS_LEAP_YEAR(year) && day > days_in_year[3]) | ||
256 | day--; | ||
257 | for (month = 1; month < 12; month++) { | ||
258 | if (days_in_year[month + 1] > day) | ||
259 | break; | ||
260 | } | ||
261 | } | ||
262 | day -= days_in_year[month]; | ||
263 | 239 | ||
264 | *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11 | 240 | *time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); |
265 | | ((second / SECS_PER_MIN) % 60) << 5 | 241 | *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); |
266 | | (second % SECS_PER_MIN) >> 1); | ||
267 | *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1)); | ||
268 | if (time_cs) | 242 | if (time_cs) |
269 | *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; | 243 | *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; |
270 | } | 244 | } |
@@ -285,4 +259,3 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | |||
285 | } | 259 | } |
286 | return err; | 260 | return err; |
287 | } | 261 | } |
288 | |||
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index e590242fa41a..3221a0c7944e 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -91,7 +91,7 @@ EXPORT_SYMBOL(fscache_object_destroy); | |||
91 | */ | 91 | */ |
92 | static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) | 92 | static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) |
93 | { | 93 | { |
94 | struct fscache_object *pobj, *obj, *minobj = NULL; | 94 | struct fscache_object *pobj, *obj = NULL, *minobj = NULL; |
95 | struct rb_node *p; | 95 | struct rb_node *p; |
96 | unsigned long pos; | 96 | unsigned long pos; |
97 | 97 | ||
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index f2feaa06bf26..cadc4ce48656 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/magic.h> | 14 | #include <linux/magic.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/smp_lock.h> | 16 | #include <linux/smp_lock.h> |
17 | #include <linux/bitmap.h> | ||
17 | 18 | ||
18 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ | 19 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ |
19 | 20 | ||
@@ -115,15 +116,13 @@ static void hpfs_put_super(struct super_block *s) | |||
115 | unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) | 116 | unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) |
116 | { | 117 | { |
117 | struct quad_buffer_head qbh; | 118 | struct quad_buffer_head qbh; |
118 | unsigned *bits; | 119 | unsigned long *bits; |
119 | unsigned i, count; | 120 | unsigned count; |
120 | if (!(bits = hpfs_map_4sectors(s, secno, &qbh, 4))) return 0; | 121 | |
121 | count = 0; | 122 | bits = hpfs_map_4sectors(s, secno, &qbh, 4); |
122 | for (i = 0; i < 2048 / sizeof(unsigned); i++) { | 123 | if (!bits) |
123 | unsigned b; | 124 | return 0; |
124 | if (!bits[i]) continue; | 125 | count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); |
125 | for (b = bits[i]; b; b>>=1) count += b & 1; | ||
126 | } | ||
127 | hpfs_brelse4(&qbh); | 126 | hpfs_brelse4(&qbh); |
128 | return count; | 127 | return count; |
129 | } | 128 | } |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index deb2b132ae5e..3dae4a13f6e4 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -547,6 +547,9 @@ bail: | |||
547 | * | 547 | * |
548 | * called like this: dio->get_blocks(dio->inode, fs_startblk, | 548 | * called like this: dio->get_blocks(dio->inode, fs_startblk, |
549 | * fs_count, map_bh, dio->rw == WRITE); | 549 | * fs_count, map_bh, dio->rw == WRITE); |
550 | * | ||
551 | * Note that we never bother to allocate blocks here, and thus ignore the | ||
552 | * create argument. | ||
550 | */ | 553 | */ |
551 | static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | 554 | static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, |
552 | struct buffer_head *bh_result, int create) | 555 | struct buffer_head *bh_result, int create) |
@@ -563,14 +566,6 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
563 | 566 | ||
564 | inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); | 567 | inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); |
565 | 568 | ||
566 | /* | ||
567 | * Any write past EOF is not allowed because we'd be extending. | ||
568 | */ | ||
569 | if (create && (iblock + max_blocks) > inode_blocks) { | ||
570 | ret = -EIO; | ||
571 | goto bail; | ||
572 | } | ||
573 | |||
574 | /* This figures out the size of the next contiguous block, and | 569 | /* This figures out the size of the next contiguous block, and |
575 | * our logical offset */ | 570 | * our logical offset */ |
576 | ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, | 571 | ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, |
@@ -582,15 +577,6 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
582 | goto bail; | 577 | goto bail; |
583 | } | 578 | } |
584 | 579 | ||
585 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno && create) { | ||
586 | ocfs2_error(inode->i_sb, | ||
587 | "Inode %llu has a hole at block %llu\n", | ||
588 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
589 | (unsigned long long)iblock); | ||
590 | ret = -EROFS; | ||
591 | goto bail; | ||
592 | } | ||
593 | |||
594 | /* We should already CoW the refcounted extent. */ | 580 | /* We should already CoW the refcounted extent. */ |
595 | BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED); | 581 | BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED); |
596 | /* | 582 | /* |
@@ -601,20 +587,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
601 | */ | 587 | */ |
602 | if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN)) | 588 | if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN)) |
603 | map_bh(bh_result, inode->i_sb, p_blkno); | 589 | map_bh(bh_result, inode->i_sb, p_blkno); |
604 | else { | 590 | else |
605 | /* | ||
606 | * ocfs2_prepare_inode_for_write() should have caught | ||
607 | * the case where we'd be filling a hole and triggered | ||
608 | * a buffered write instead. | ||
609 | */ | ||
610 | if (create) { | ||
611 | ret = -EIO; | ||
612 | mlog_errno(ret); | ||
613 | goto bail; | ||
614 | } | ||
615 | |||
616 | clear_buffer_mapped(bh_result); | 591 | clear_buffer_mapped(bh_result); |
617 | } | ||
618 | 592 | ||
619 | /* make sure we don't map more than max_blocks blocks here as | 593 | /* make sure we don't map more than max_blocks blocks here as |
620 | that's all the kernel will handle at this point. */ | 594 | that's all the kernel will handle at this point. */ |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 4df4a464a919..18d5cc62d8ed 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2266,7 +2266,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = { | |||
2266 | 2266 | ||
2267 | #endif | 2267 | #endif |
2268 | 2268 | ||
2269 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2269 | #ifdef CONFIG_ELF_CORE |
2270 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, | 2270 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, |
2271 | size_t count, loff_t *ppos) | 2271 | size_t count, loff_t *ppos) |
2272 | { | 2272 | { |
@@ -2623,7 +2623,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2623 | #ifdef CONFIG_FAULT_INJECTION | 2623 | #ifdef CONFIG_FAULT_INJECTION |
2624 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 2624 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
2625 | #endif | 2625 | #endif |
2626 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2626 | #ifdef CONFIG_ELF_CORE |
2627 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), | 2627 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), |
2628 | #endif | 2628 | #endif |
2629 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2629 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index fa678abc9db1..480cb1065eec 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -429,7 +429,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
429 | unsigned int ino; | 429 | unsigned int ino; |
430 | 430 | ||
431 | ino = de->low_ino; | 431 | ino = de->low_ino; |
432 | de_get(de); | 432 | pde_get(de); |
433 | spin_unlock(&proc_subdir_lock); | 433 | spin_unlock(&proc_subdir_lock); |
434 | error = -EINVAL; | 434 | error = -EINVAL; |
435 | inode = proc_get_inode(dir->i_sb, ino, de); | 435 | inode = proc_get_inode(dir->i_sb, ino, de); |
@@ -445,7 +445,7 @@ out_unlock: | |||
445 | return NULL; | 445 | return NULL; |
446 | } | 446 | } |
447 | if (de) | 447 | if (de) |
448 | de_put(de); | 448 | pde_put(de); |
449 | return ERR_PTR(error); | 449 | return ERR_PTR(error); |
450 | } | 450 | } |
451 | 451 | ||
@@ -509,17 +509,17 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | |||
509 | struct proc_dir_entry *next; | 509 | struct proc_dir_entry *next; |
510 | 510 | ||
511 | /* filldir passes info to user space */ | 511 | /* filldir passes info to user space */ |
512 | de_get(de); | 512 | pde_get(de); |
513 | spin_unlock(&proc_subdir_lock); | 513 | spin_unlock(&proc_subdir_lock); |
514 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, | 514 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, |
515 | de->low_ino, de->mode >> 12) < 0) { | 515 | de->low_ino, de->mode >> 12) < 0) { |
516 | de_put(de); | 516 | pde_put(de); |
517 | goto out; | 517 | goto out; |
518 | } | 518 | } |
519 | spin_lock(&proc_subdir_lock); | 519 | spin_lock(&proc_subdir_lock); |
520 | filp->f_pos++; | 520 | filp->f_pos++; |
521 | next = de->next; | 521 | next = de->next; |
522 | de_put(de); | 522 | pde_put(de); |
523 | de = next; | 523 | de = next; |
524 | } while (de); | 524 | } while (de); |
525 | spin_unlock(&proc_subdir_lock); | 525 | spin_unlock(&proc_subdir_lock); |
@@ -763,7 +763,7 @@ out: | |||
763 | return NULL; | 763 | return NULL; |
764 | } | 764 | } |
765 | 765 | ||
766 | void free_proc_entry(struct proc_dir_entry *de) | 766 | static void free_proc_entry(struct proc_dir_entry *de) |
767 | { | 767 | { |
768 | unsigned int ino = de->low_ino; | 768 | unsigned int ino = de->low_ino; |
769 | 769 | ||
@@ -777,6 +777,12 @@ void free_proc_entry(struct proc_dir_entry *de) | |||
777 | kfree(de); | 777 | kfree(de); |
778 | } | 778 | } |
779 | 779 | ||
780 | void pde_put(struct proc_dir_entry *pde) | ||
781 | { | ||
782 | if (atomic_dec_and_test(&pde->count)) | ||
783 | free_proc_entry(pde); | ||
784 | } | ||
785 | |||
780 | /* | 786 | /* |
781 | * Remove a /proc entry and free it if it's not currently in use. | 787 | * Remove a /proc entry and free it if it's not currently in use. |
782 | */ | 788 | */ |
@@ -845,6 +851,5 @@ continue_removing: | |||
845 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " | 851 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " |
846 | "'%s/%s', leaking at least '%s'\n", __func__, | 852 | "'%s/%s', leaking at least '%s'\n", __func__, |
847 | de->parent->name, de->name, de->subdir->name); | 853 | de->parent->name, de->name, de->subdir->name); |
848 | if (atomic_dec_and_test(&de->count)) | 854 | pde_put(de); |
849 | free_proc_entry(de); | ||
850 | } | 855 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d78ade305541..445a02bcaab3 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -24,29 +24,6 @@ | |||
24 | 24 | ||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | 26 | ||
27 | struct proc_dir_entry *de_get(struct proc_dir_entry *de) | ||
28 | { | ||
29 | atomic_inc(&de->count); | ||
30 | return de; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Decrements the use count and checks for deferred deletion. | ||
35 | */ | ||
36 | void de_put(struct proc_dir_entry *de) | ||
37 | { | ||
38 | if (!atomic_read(&de->count)) { | ||
39 | printk("de_put: entry %s already free!\n", de->name); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | if (atomic_dec_and_test(&de->count)) | ||
44 | free_proc_entry(de); | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Decrement the use count of the proc_dir_entry. | ||
49 | */ | ||
50 | static void proc_delete_inode(struct inode *inode) | 27 | static void proc_delete_inode(struct inode *inode) |
51 | { | 28 | { |
52 | struct proc_dir_entry *de; | 29 | struct proc_dir_entry *de; |
@@ -59,7 +36,7 @@ static void proc_delete_inode(struct inode *inode) | |||
59 | /* Let go of any associated proc directory entry */ | 36 | /* Let go of any associated proc directory entry */ |
60 | de = PROC_I(inode)->pde; | 37 | de = PROC_I(inode)->pde; |
61 | if (de) | 38 | if (de) |
62 | de_put(de); | 39 | pde_put(de); |
63 | if (PROC_I(inode)->sysctl) | 40 | if (PROC_I(inode)->sysctl) |
64 | sysctl_head_put(PROC_I(inode)->sysctl); | 41 | sysctl_head_put(PROC_I(inode)->sysctl); |
65 | clear_inode(inode); | 42 | clear_inode(inode); |
@@ -480,7 +457,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
480 | } | 457 | } |
481 | unlock_new_inode(inode); | 458 | unlock_new_inode(inode); |
482 | } else | 459 | } else |
483 | de_put(de); | 460 | pde_put(de); |
484 | return inode; | 461 | return inode; |
485 | } | 462 | } |
486 | 463 | ||
@@ -495,7 +472,7 @@ int proc_fill_super(struct super_block *s) | |||
495 | s->s_op = &proc_sops; | 472 | s->s_op = &proc_sops; |
496 | s->s_time_gran = 1; | 473 | s->s_time_gran = 1; |
497 | 474 | ||
498 | de_get(&proc_root); | 475 | pde_get(&proc_root); |
499 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); | 476 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); |
500 | if (!root_inode) | 477 | if (!root_inode) |
501 | goto out_no_root; | 478 | goto out_no_root; |
@@ -509,6 +486,6 @@ int proc_fill_super(struct super_block *s) | |||
509 | out_no_root: | 486 | out_no_root: |
510 | printk("proc_read_super: get root inode failed\n"); | 487 | printk("proc_read_super: get root inode failed\n"); |
511 | iput(root_inode); | 488 | iput(root_inode); |
512 | de_put(&proc_root); | 489 | pde_put(&proc_root); |
513 | return -ENOMEM; | 490 | return -ENOMEM; |
514 | } | 491 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 753ca37002c8..1f24a3eddd12 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -61,8 +61,6 @@ extern const struct file_operations proc_pagemap_operations; | |||
61 | extern const struct file_operations proc_net_operations; | 61 | extern const struct file_operations proc_net_operations; |
62 | extern const struct inode_operations proc_net_inode_operations; | 62 | extern const struct inode_operations proc_net_inode_operations; |
63 | 63 | ||
64 | void free_proc_entry(struct proc_dir_entry *de); | ||
65 | |||
66 | void proc_init_inodecache(void); | 64 | void proc_init_inodecache(void); |
67 | 65 | ||
68 | static inline struct pid *proc_pid(struct inode *inode) | 66 | static inline struct pid *proc_pid(struct inode *inode) |
@@ -101,8 +99,12 @@ unsigned long task_vsize(struct mm_struct *); | |||
101 | int task_statm(struct mm_struct *, int *, int *, int *, int *); | 99 | int task_statm(struct mm_struct *, int *, int *, int *, int *); |
102 | void task_mem(struct seq_file *, struct mm_struct *); | 100 | void task_mem(struct seq_file *, struct mm_struct *); |
103 | 101 | ||
104 | struct proc_dir_entry *de_get(struct proc_dir_entry *de); | 102 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
105 | void de_put(struct proc_dir_entry *de); | 103 | { |
104 | atomic_inc(&pde->count); | ||
105 | return pde; | ||
106 | } | ||
107 | void pde_put(struct proc_dir_entry *pde); | ||
106 | 108 | ||
107 | extern struct vfsmount *proc_mnt; | 109 | extern struct vfsmount *proc_mnt; |
108 | int proc_fill_super(struct super_block *); | 110 | int proc_fill_super(struct super_block *); |
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c index 32f5d131a644..22e0d60e53ef 100644 --- a/fs/qnx4/bitmap.c +++ b/fs/qnx4/bitmap.c | |||
@@ -17,13 +17,6 @@ | |||
17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
18 | #include "qnx4.h" | 18 | #include "qnx4.h" |
19 | 19 | ||
20 | #if 0 | ||
21 | int qnx4_new_block(struct super_block *sb) | ||
22 | { | ||
23 | return 0; | ||
24 | } | ||
25 | #endif /* 0 */ | ||
26 | |||
27 | static void count_bits(register const char *bmPart, register int size, | 20 | static void count_bits(register const char *bmPart, register int size, |
28 | int *const tf) | 21 | int *const tf) |
29 | { | 22 | { |
@@ -35,22 +28,7 @@ static void count_bits(register const char *bmPart, register int size, | |||
35 | } | 28 | } |
36 | do { | 29 | do { |
37 | b = *bmPart++; | 30 | b = *bmPart++; |
38 | if ((b & 1) == 0) | 31 | tot += 8 - hweight8(b); |
39 | tot++; | ||
40 | if ((b & 2) == 0) | ||
41 | tot++; | ||
42 | if ((b & 4) == 0) | ||
43 | tot++; | ||
44 | if ((b & 8) == 0) | ||
45 | tot++; | ||
46 | if ((b & 16) == 0) | ||
47 | tot++; | ||
48 | if ((b & 32) == 0) | ||
49 | tot++; | ||
50 | if ((b & 64) == 0) | ||
51 | tot++; | ||
52 | if ((b & 128) == 0) | ||
53 | tot++; | ||
54 | size--; | 32 | size--; |
55 | } while (size != 0); | 33 | } while (size != 0); |
56 | *tf = tot; | 34 | *tf = tot; |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 449f5a66dd34..ebf3440d28ca 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
@@ -64,25 +64,7 @@ static struct buffer_head *qnx4_getblk(struct inode *inode, int nr, | |||
64 | result = sb_getblk(inode->i_sb, nr); | 64 | result = sb_getblk(inode->i_sb, nr); |
65 | return result; | 65 | return result; |
66 | } | 66 | } |
67 | if (!create) { | 67 | return NULL; |
68 | return NULL; | ||
69 | } | ||
70 | #if 0 | ||
71 | tmp = qnx4_new_block(inode->i_sb); | ||
72 | if (!tmp) { | ||
73 | return NULL; | ||
74 | } | ||
75 | result = sb_getblk(inode->i_sb, tmp); | ||
76 | if (tst) { | ||
77 | qnx4_free_block(inode->i_sb, tmp); | ||
78 | brelse(result); | ||
79 | goto repeat; | ||
80 | } | ||
81 | tst = tmp; | ||
82 | #endif | ||
83 | inode->i_ctime = CURRENT_TIME_SEC; | ||
84 | mark_inode_dirty(inode); | ||
85 | return result; | ||
86 | } | 68 | } |
87 | 69 | ||
88 | struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) | 70 | struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) |
@@ -113,8 +95,6 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h | |||
113 | if ( phys ) { | 95 | if ( phys ) { |
114 | // logical block is before EOF | 96 | // logical block is before EOF |
115 | map_bh(bh, inode->i_sb, phys); | 97 | map_bh(bh, inode->i_sb, phys); |
116 | } else if ( create ) { | ||
117 | // to be done. | ||
118 | } | 98 | } |
119 | return 0; | 99 | return 0; |
120 | } | 100 | } |
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile index 6a9e30c041dd..792b3cb2cd18 100644 --- a/fs/reiserfs/Makefile +++ b/fs/reiserfs/Makefile | |||
@@ -7,7 +7,11 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o | |||
7 | reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ | 7 | reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ |
8 | super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ | 8 | super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ |
9 | hashes.o tail_conversion.o journal.o resize.o \ | 9 | hashes.o tail_conversion.o journal.o resize.o \ |
10 | item_ops.o ioctl.o procfs.o xattr.o lock.o | 10 | item_ops.o ioctl.o xattr.o lock.o |
11 | |||
12 | ifeq ($(CONFIG_REISERFS_PROC_INFO),y) | ||
13 | reiserfs-objs += procfs.o | ||
14 | endif | ||
11 | 15 | ||
12 | ifeq ($(CONFIG_REISERFS_FS_XATTR),y) | 16 | ifeq ($(CONFIG_REISERFS_FS_XATTR),y) |
13 | reiserfs-objs += xattr_user.o xattr_trusted.o | 17 | reiserfs-objs += xattr_user.o xattr_trusted.o |
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 9229e5514a4e..7a9981196c1c 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/proc_fs.h> | 18 | #include <linux/proc_fs.h> |
19 | 19 | ||
20 | #ifdef CONFIG_REISERFS_PROC_INFO | ||
21 | |||
22 | /* | 20 | /* |
23 | * LOCKING: | 21 | * LOCKING: |
24 | * | 22 | * |
@@ -48,14 +46,6 @@ static int show_version(struct seq_file *m, struct super_block *sb) | |||
48 | return 0; | 46 | return 0; |
49 | } | 47 | } |
50 | 48 | ||
51 | int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset, | ||
52 | int count, int *eof, void *data) | ||
53 | { | ||
54 | *start = buffer; | ||
55 | *eof = 1; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | #define SF( x ) ( r -> x ) | 49 | #define SF( x ) ( r -> x ) |
60 | #define SFP( x ) SF( s_proc_info_data.x ) | 50 | #define SFP( x ) SF( s_proc_info_data.x ) |
61 | #define SFPL( x ) SFP( x[ level ] ) | 51 | #define SFPL( x ) SFP( x[ level ] ) |
@@ -538,19 +528,6 @@ int reiserfs_proc_info_done(struct super_block *sb) | |||
538 | return 0; | 528 | return 0; |
539 | } | 529 | } |
540 | 530 | ||
541 | struct proc_dir_entry *reiserfs_proc_register_global(char *name, | ||
542 | read_proc_t * func) | ||
543 | { | ||
544 | return (proc_info_root) ? create_proc_read_entry(name, 0, | ||
545 | proc_info_root, | ||
546 | func, NULL) : NULL; | ||
547 | } | ||
548 | |||
549 | void reiserfs_proc_unregister_global(const char *name) | ||
550 | { | ||
551 | remove_proc_entry(name, proc_info_root); | ||
552 | } | ||
553 | |||
554 | int reiserfs_proc_info_global_init(void) | 531 | int reiserfs_proc_info_global_init(void) |
555 | { | 532 | { |
556 | if (proc_info_root == NULL) { | 533 | if (proc_info_root == NULL) { |
@@ -572,48 +549,6 @@ int reiserfs_proc_info_global_done(void) | |||
572 | } | 549 | } |
573 | return 0; | 550 | return 0; |
574 | } | 551 | } |
575 | |||
576 | /* REISERFS_PROC_INFO */ | ||
577 | #else | ||
578 | |||
579 | int reiserfs_proc_info_init(struct super_block *sb) | ||
580 | { | ||
581 | return 0; | ||
582 | } | ||
583 | int reiserfs_proc_info_done(struct super_block *sb) | ||
584 | { | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | struct proc_dir_entry *reiserfs_proc_register_global(char *name, | ||
589 | read_proc_t * func) | ||
590 | { | ||
591 | return NULL; | ||
592 | } | ||
593 | |||
594 | void reiserfs_proc_unregister_global(const char *name) | ||
595 | {; | ||
596 | } | ||
597 | |||
598 | int reiserfs_proc_info_global_init(void) | ||
599 | { | ||
600 | return 0; | ||
601 | } | ||
602 | int reiserfs_proc_info_global_done(void) | ||
603 | { | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | int reiserfs_global_version_in_proc(char *buffer, char **start, | ||
608 | off_t offset, | ||
609 | int count, int *eof, void *data) | ||
610 | { | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /* REISERFS_PROC_INFO */ | ||
615 | #endif | ||
616 | |||
617 | /* | 552 | /* |
618 | * Revision 1.1.8.2 2001/07/15 17:08:42 god | 553 | * Revision 1.1.8.2 2001/07/15 17:08:42 god |
619 | * . use get_super() in procfs.c | 554 | * . use get_super() in procfs.c |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 339b0baf2af6..b4a7dd03bdb9 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -2222,8 +2222,6 @@ static int __init init_reiserfs_fs(void) | |||
2222 | } | 2222 | } |
2223 | 2223 | ||
2224 | reiserfs_proc_info_global_init(); | 2224 | reiserfs_proc_info_global_init(); |
2225 | reiserfs_proc_register_global("version", | ||
2226 | reiserfs_global_version_in_proc); | ||
2227 | 2225 | ||
2228 | ret = register_filesystem(&reiserfs_fs_type); | 2226 | ret = register_filesystem(&reiserfs_fs_type); |
2229 | 2227 | ||
@@ -2231,7 +2229,6 @@ static int __init init_reiserfs_fs(void) | |||
2231 | return 0; | 2229 | return 0; |
2232 | } | 2230 | } |
2233 | 2231 | ||
2234 | reiserfs_proc_unregister_global("version"); | ||
2235 | reiserfs_proc_info_global_done(); | 2232 | reiserfs_proc_info_global_done(); |
2236 | destroy_inodecache(); | 2233 | destroy_inodecache(); |
2237 | 2234 | ||
@@ -2240,7 +2237,6 @@ static int __init init_reiserfs_fs(void) | |||
2240 | 2237 | ||
2241 | static void __exit exit_reiserfs_fs(void) | 2238 | static void __exit exit_reiserfs_fs(void) |
2242 | { | 2239 | { |
2243 | reiserfs_proc_unregister_global("version"); | ||
2244 | reiserfs_proc_info_global_done(); | 2240 | reiserfs_proc_info_global_done(); |
2245 | unregister_filesystem(&reiserfs_fs_type); | 2241 | unregister_filesystem(&reiserfs_fs_type); |
2246 | destroy_inodecache(); | 2242 | destroy_inodecache(); |
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 6f671f1ac271..22af68f8b682 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c | |||
@@ -70,13 +70,13 @@ static inline unsigned long ufs_dir_pages(struct inode *inode) | |||
70 | return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; | 70 | return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; |
71 | } | 71 | } |
72 | 72 | ||
73 | ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry) | 73 | ino_t ufs_inode_by_name(struct inode *dir, struct qstr *qstr) |
74 | { | 74 | { |
75 | ino_t res = 0; | 75 | ino_t res = 0; |
76 | struct ufs_dir_entry *de; | 76 | struct ufs_dir_entry *de; |
77 | struct page *page; | 77 | struct page *page; |
78 | 78 | ||
79 | de = ufs_find_entry(dir, dentry, &page); | 79 | de = ufs_find_entry(dir, qstr, &page); |
80 | if (de) { | 80 | if (de) { |
81 | res = fs32_to_cpu(dir->i_sb, de->d_ino); | 81 | res = fs32_to_cpu(dir->i_sb, de->d_ino); |
82 | ufs_put_page(page); | 82 | ufs_put_page(page); |
@@ -249,12 +249,12 @@ struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p) | |||
249 | * (as a parameter - res_dir). Page is returned mapped and unlocked. | 249 | * (as a parameter - res_dir). Page is returned mapped and unlocked. |
250 | * Entry is guaranteed to be valid. | 250 | * Entry is guaranteed to be valid. |
251 | */ | 251 | */ |
252 | struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry, | 252 | struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct qstr *qstr, |
253 | struct page **res_page) | 253 | struct page **res_page) |
254 | { | 254 | { |
255 | struct super_block *sb = dir->i_sb; | 255 | struct super_block *sb = dir->i_sb; |
256 | const char *name = dentry->d_name.name; | 256 | const char *name = qstr->name; |
257 | int namelen = dentry->d_name.len; | 257 | int namelen = qstr->len; |
258 | unsigned reclen = UFS_DIR_REC_LEN(namelen); | 258 | unsigned reclen = UFS_DIR_REC_LEN(namelen); |
259 | unsigned long start, n; | 259 | unsigned long start, n; |
260 | unsigned long npages = ufs_dir_pages(dir); | 260 | unsigned long npages = ufs_dir_pages(dir); |
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 23119fe7ad62..4c26d9e8bc94 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c | |||
@@ -56,7 +56,7 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru | |||
56 | return ERR_PTR(-ENAMETOOLONG); | 56 | return ERR_PTR(-ENAMETOOLONG); |
57 | 57 | ||
58 | lock_kernel(); | 58 | lock_kernel(); |
59 | ino = ufs_inode_by_name(dir, dentry); | 59 | ino = ufs_inode_by_name(dir, &dentry->d_name); |
60 | if (ino) { | 60 | if (ino) { |
61 | inode = ufs_iget(dir->i_sb, ino); | 61 | inode = ufs_iget(dir->i_sb, ino); |
62 | if (IS_ERR(inode)) { | 62 | if (IS_ERR(inode)) { |
@@ -237,7 +237,7 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry) | |||
237 | struct page *page; | 237 | struct page *page; |
238 | int err = -ENOENT; | 238 | int err = -ENOENT; |
239 | 239 | ||
240 | de = ufs_find_entry(dir, dentry, &page); | 240 | de = ufs_find_entry(dir, &dentry->d_name, &page); |
241 | if (!de) | 241 | if (!de) |
242 | goto out; | 242 | goto out; |
243 | 243 | ||
@@ -281,7 +281,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
281 | struct ufs_dir_entry *old_de; | 281 | struct ufs_dir_entry *old_de; |
282 | int err = -ENOENT; | 282 | int err = -ENOENT; |
283 | 283 | ||
284 | old_de = ufs_find_entry(old_dir, old_dentry, &old_page); | 284 | old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page); |
285 | if (!old_de) | 285 | if (!old_de) |
286 | goto out; | 286 | goto out; |
287 | 287 | ||
@@ -301,7 +301,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
301 | goto out_dir; | 301 | goto out_dir; |
302 | 302 | ||
303 | err = -ENOENT; | 303 | err = -ENOENT; |
304 | new_de = ufs_find_entry(new_dir, new_dentry, &new_page); | 304 | new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page); |
305 | if (!new_de) | 305 | if (!new_de) |
306 | goto out_dir; | 306 | goto out_dir; |
307 | inode_inc_link_count(old_inode); | 307 | inode_inc_link_count(old_inode); |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 5faed7954d0a..143c20bfb04b 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
@@ -66,6 +66,7 @@ | |||
66 | */ | 66 | */ |
67 | 67 | ||
68 | 68 | ||
69 | #include <linux/exportfs.h> | ||
69 | #include <linux/module.h> | 70 | #include <linux/module.h> |
70 | #include <linux/bitops.h> | 71 | #include <linux/bitops.h> |
71 | 72 | ||
@@ -96,6 +97,56 @@ | |||
96 | #include "swab.h" | 97 | #include "swab.h" |
97 | #include "util.h" | 98 | #include "util.h" |
98 | 99 | ||
100 | static struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) | ||
101 | { | ||
102 | struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | ||
103 | struct inode *inode; | ||
104 | |||
105 | if (ino < UFS_ROOTINO || ino > uspi->s_ncg * uspi->s_ipg) | ||
106 | return ERR_PTR(-ESTALE); | ||
107 | |||
108 | inode = ufs_iget(sb, ino); | ||
109 | if (IS_ERR(inode)) | ||
110 | return ERR_CAST(inode); | ||
111 | if (generation && inode->i_generation != generation) { | ||
112 | iput(inode); | ||
113 | return ERR_PTR(-ESTALE); | ||
114 | } | ||
115 | return inode; | ||
116 | } | ||
117 | |||
118 | static struct dentry *ufs_fh_to_dentry(struct super_block *sb, struct fid *fid, | ||
119 | int fh_len, int fh_type) | ||
120 | { | ||
121 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); | ||
122 | } | ||
123 | |||
124 | static struct dentry *ufs_fh_to_parent(struct super_block *sb, struct fid *fid, | ||
125 | int fh_len, int fh_type) | ||
126 | { | ||
127 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); | ||
128 | } | ||
129 | |||
130 | static struct dentry *ufs_get_parent(struct dentry *child) | ||
131 | { | ||
132 | struct qstr dot_dot = { | ||
133 | .name = "..", | ||
134 | .len = 2, | ||
135 | }; | ||
136 | ino_t ino; | ||
137 | |||
138 | ino = ufs_inode_by_name(child->d_inode, &dot_dot); | ||
139 | if (!ino) | ||
140 | return ERR_PTR(-ENOENT); | ||
141 | return d_obtain_alias(ufs_iget(child->d_inode->i_sb, ino)); | ||
142 | } | ||
143 | |||
144 | static const struct export_operations ufs_export_ops = { | ||
145 | .fh_to_dentry = ufs_fh_to_dentry, | ||
146 | .fh_to_parent = ufs_fh_to_parent, | ||
147 | .get_parent = ufs_get_parent, | ||
148 | }; | ||
149 | |||
99 | #ifdef CONFIG_UFS_DEBUG | 150 | #ifdef CONFIG_UFS_DEBUG |
100 | /* | 151 | /* |
101 | * Print contents of ufs_super_block, useful for debugging | 152 | * Print contents of ufs_super_block, useful for debugging |
@@ -990,6 +1041,7 @@ magic_found: | |||
990 | * Read ufs_super_block into internal data structures | 1041 | * Read ufs_super_block into internal data structures |
991 | */ | 1042 | */ |
992 | sb->s_op = &ufs_super_ops; | 1043 | sb->s_op = &ufs_super_ops; |
1044 | sb->s_export_op = &ufs_export_ops; | ||
993 | sb->dq_op = NULL; /***/ | 1045 | sb->dq_op = NULL; /***/ |
994 | sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); | 1046 | sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); |
995 | 1047 | ||
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 644e77e13599..0b4c39bc0d9e 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h | |||
@@ -86,9 +86,9 @@ extern void ufs_put_cylinder (struct super_block *, unsigned); | |||
86 | /* dir.c */ | 86 | /* dir.c */ |
87 | extern const struct inode_operations ufs_dir_inode_operations; | 87 | extern const struct inode_operations ufs_dir_inode_operations; |
88 | extern int ufs_add_link (struct dentry *, struct inode *); | 88 | extern int ufs_add_link (struct dentry *, struct inode *); |
89 | extern ino_t ufs_inode_by_name(struct inode *, struct dentry *); | 89 | extern ino_t ufs_inode_by_name(struct inode *, struct qstr *); |
90 | extern int ufs_make_empty(struct inode *, struct inode *); | 90 | extern int ufs_make_empty(struct inode *, struct inode *); |
91 | extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **); | 91 | extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct qstr *, struct page **); |
92 | extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *); | 92 | extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *); |
93 | extern int ufs_empty_dir (struct inode *); | 93 | extern int ufs_empty_dir (struct inode *); |
94 | extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **); | 94 | extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **); |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index d798c54296eb..66abe36c1213 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -1474,19 +1474,13 @@ xfs_vm_direct_IO( | |||
1474 | 1474 | ||
1475 | bdev = xfs_find_bdev_for_inode(XFS_I(inode)); | 1475 | bdev = xfs_find_bdev_for_inode(XFS_I(inode)); |
1476 | 1476 | ||
1477 | if (rw == WRITE) { | 1477 | iocb->private = xfs_alloc_ioend(inode, rw == WRITE ? |
1478 | iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); | 1478 | IOMAP_UNWRITTEN : IOMAP_READ); |
1479 | ret = blockdev_direct_IO_own_locking(rw, iocb, inode, | 1479 | |
1480 | bdev, iov, offset, nr_segs, | 1480 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov, |
1481 | xfs_get_blocks_direct, | 1481 | offset, nr_segs, |
1482 | xfs_end_io_direct); | 1482 | xfs_get_blocks_direct, |
1483 | } else { | 1483 | xfs_end_io_direct); |
1484 | iocb->private = xfs_alloc_ioend(inode, IOMAP_READ); | ||
1485 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, | ||
1486 | bdev, iov, offset, nr_segs, | ||
1487 | xfs_get_blocks_direct, | ||
1488 | xfs_end_io_direct); | ||
1489 | } | ||
1490 | 1484 | ||
1491 | if (unlikely(ret != -EIOCBQUEUED && iocb->private)) | 1485 | if (unlikely(ret != -EIOCBQUEUED && iocb->private)) |
1492 | xfs_destroy_ioend(iocb->private); | 1486 | xfs_destroy_ioend(iocb->private); |
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 204bed37e82d..485eeb6c4ef3 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h | |||
@@ -145,6 +145,7 @@ extern int __gpio_to_irq(unsigned gpio); | |||
145 | extern int gpio_export(unsigned gpio, bool direction_may_change); | 145 | extern int gpio_export(unsigned gpio, bool direction_may_change); |
146 | extern int gpio_export_link(struct device *dev, const char *name, | 146 | extern int gpio_export_link(struct device *dev, const char *name, |
147 | unsigned gpio); | 147 | unsigned gpio); |
148 | extern int gpio_sysfs_set_active_low(unsigned gpio, int value); | ||
148 | extern void gpio_unexport(unsigned gpio); | 149 | extern void gpio_unexport(unsigned gpio); |
149 | 150 | ||
150 | #endif /* CONFIG_GPIO_SYSFS */ | 151 | #endif /* CONFIG_GPIO_SYSFS */ |
@@ -197,6 +198,11 @@ static inline int gpio_export_link(struct device *dev, const char *name, | |||
197 | return -ENOSYS; | 198 | return -ENOSYS; |
198 | } | 199 | } |
199 | 200 | ||
201 | static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) | ||
202 | { | ||
203 | return -ENOSYS; | ||
204 | } | ||
205 | |||
200 | static inline void gpio_unexport(unsigned gpio) | 206 | static inline void gpio_unexport(unsigned gpio) |
201 | { | 207 | { |
202 | } | 208 | } |
diff --git a/include/linux/aio.h b/include/linux/aio.h index aea219d7d8d1..811dbb369379 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
@@ -102,7 +102,6 @@ struct kiocb { | |||
102 | } ki_obj; | 102 | } ki_obj; |
103 | 103 | ||
104 | __u64 ki_user_data; /* user's data for completion */ | 104 | __u64 ki_user_data; /* user's data for completion */ |
105 | wait_queue_t ki_wait; | ||
106 | loff_t ki_pos; | 105 | loff_t ki_pos; |
107 | 106 | ||
108 | void *private; | 107 | void *private; |
@@ -140,7 +139,6 @@ struct kiocb { | |||
140 | (x)->ki_dtor = NULL; \ | 139 | (x)->ki_dtor = NULL; \ |
141 | (x)->ki_obj.tsk = tsk; \ | 140 | (x)->ki_obj.tsk = tsk; \ |
142 | (x)->ki_user_data = 0; \ | 141 | (x)->ki_user_data = 0; \ |
143 | init_wait((&(x)->ki_wait)); \ | ||
144 | } while (0) | 142 | } while (0) |
145 | 143 | ||
146 | #define AIO_RING_MAGIC 0xa10a10a1 | 144 | #define AIO_RING_MAGIC 0xa10a10a1 |
@@ -223,8 +221,6 @@ struct mm_struct; | |||
223 | static inline void exit_aio(struct mm_struct *mm) { } | 221 | static inline void exit_aio(struct mm_struct *mm) { } |
224 | #endif /* CONFIG_AIO */ | 222 | #endif /* CONFIG_AIO */ |
225 | 223 | ||
226 | #define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait) | ||
227 | |||
228 | static inline struct kiocb *list_kiocb(struct list_head *h) | 224 | static inline struct kiocb *list_kiocb(struct list_head *h) |
229 | { | 225 | { |
230 | return list_entry(h, struct kiocb, ki_list); | 226 | return list_entry(h, struct kiocb, ki_list); |
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 756d78b8c1c5..daf8c480c786 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h | |||
@@ -42,6 +42,9 @@ | |||
42 | * bitmap_empty(src, nbits) Are all bits zero in *src? | 42 | * bitmap_empty(src, nbits) Are all bits zero in *src? |
43 | * bitmap_full(src, nbits) Are all bits set in *src? | 43 | * bitmap_full(src, nbits) Are all bits set in *src? |
44 | * bitmap_weight(src, nbits) Hamming Weight: number set bits | 44 | * bitmap_weight(src, nbits) Hamming Weight: number set bits |
45 | * bitmap_set(dst, pos, nbits) Set specified bit area | ||
46 | * bitmap_clear(dst, pos, nbits) Clear specified bit area | ||
47 | * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area | ||
45 | * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n | 48 | * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n |
46 | * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n | 49 | * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n |
47 | * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) | 50 | * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) |
@@ -108,6 +111,14 @@ extern int __bitmap_subset(const unsigned long *bitmap1, | |||
108 | const unsigned long *bitmap2, int bits); | 111 | const unsigned long *bitmap2, int bits); |
109 | extern int __bitmap_weight(const unsigned long *bitmap, int bits); | 112 | extern int __bitmap_weight(const unsigned long *bitmap, int bits); |
110 | 113 | ||
114 | extern void bitmap_set(unsigned long *map, int i, int len); | ||
115 | extern void bitmap_clear(unsigned long *map, int start, int nr); | ||
116 | extern unsigned long bitmap_find_next_zero_area(unsigned long *map, | ||
117 | unsigned long size, | ||
118 | unsigned long start, | ||
119 | unsigned int nr, | ||
120 | unsigned long align_mask); | ||
121 | |||
111 | extern int bitmap_scnprintf(char *buf, unsigned int len, | 122 | extern int bitmap_scnprintf(char *buf, unsigned int len, |
112 | const unsigned long *src, int nbits); | 123 | const unsigned long *src, int nbits); |
113 | extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user, | 124 | extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index a057f48eb156..b23a7018eb90 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2264,9 +2264,11 @@ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
2264 | int lock_type); | 2264 | int lock_type); |
2265 | 2265 | ||
2266 | enum { | 2266 | enum { |
2267 | DIO_LOCKING = 1, /* need locking between buffered and direct access */ | 2267 | /* need locking between buffered and direct access */ |
2268 | DIO_NO_LOCKING, /* bdev; no locking at all between buffered/direct */ | 2268 | DIO_LOCKING = 0x01, |
2269 | DIO_OWN_LOCKING, /* filesystem locks buffered and direct internally */ | 2269 | |
2270 | /* filesystem does not support filling holes */ | ||
2271 | DIO_SKIP_HOLES = 0x02, | ||
2270 | }; | 2272 | }; |
2271 | 2273 | ||
2272 | static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, | 2274 | static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, |
@@ -2275,7 +2277,8 @@ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, | |||
2275 | dio_iodone_t end_io) | 2277 | dio_iodone_t end_io) |
2276 | { | 2278 | { |
2277 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, | 2279 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, |
2278 | nr_segs, get_block, end_io, DIO_LOCKING); | 2280 | nr_segs, get_block, end_io, |
2281 | DIO_LOCKING | DIO_SKIP_HOLES); | ||
2279 | } | 2282 | } |
2280 | 2283 | ||
2281 | static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb, | 2284 | static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb, |
@@ -2284,16 +2287,7 @@ static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb, | |||
2284 | dio_iodone_t end_io) | 2287 | dio_iodone_t end_io) |
2285 | { | 2288 | { |
2286 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, | 2289 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, |
2287 | nr_segs, get_block, end_io, DIO_NO_LOCKING); | 2290 | nr_segs, get_block, end_io, 0); |
2288 | } | ||
2289 | |||
2290 | static inline ssize_t blockdev_direct_IO_own_locking(int rw, struct kiocb *iocb, | ||
2291 | struct inode *inode, struct block_device *bdev, const struct iovec *iov, | ||
2292 | loff_t offset, unsigned long nr_segs, get_block_t get_block, | ||
2293 | dio_iodone_t end_io) | ||
2294 | { | ||
2295 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset, | ||
2296 | nr_segs, get_block, end_io, DIO_OWN_LOCKING); | ||
2297 | } | 2291 | } |
2298 | #endif | 2292 | #endif |
2299 | 2293 | ||
diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 059bd189d35d..4e949a5b5b85 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h | |||
@@ -99,6 +99,12 @@ static inline int gpio_export_link(struct device *dev, const char *name, | |||
99 | return -EINVAL; | 99 | return -EINVAL; |
100 | } | 100 | } |
101 | 101 | ||
102 | static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) | ||
103 | { | ||
104 | /* GPIO can never have been requested */ | ||
105 | WARN_ON(1); | ||
106 | return -EINVAL; | ||
107 | } | ||
102 | 108 | ||
103 | static inline void gpio_unexport(unsigned gpio) | 109 | static inline void gpio_unexport(unsigned gpio) |
104 | { | 110 | { |
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 4f0a72a9740c..9310c699a37d 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h | |||
@@ -332,6 +332,7 @@ struct intel_iommu { | |||
332 | #ifdef CONFIG_INTR_REMAP | 332 | #ifdef CONFIG_INTR_REMAP |
333 | struct ir_table *ir_table; /* Interrupt remapping info */ | 333 | struct ir_table *ir_table; /* Interrupt remapping info */ |
334 | #endif | 334 | #endif |
335 | int node; | ||
335 | }; | 336 | }; |
336 | 337 | ||
337 | static inline void __iommu_flush_cache( | 338 | static inline void __iommu_flush_cache( |
diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h index 3b068e5b5671..64d1b638745d 100644 --- a/include/linux/iommu-helper.h +++ b/include/linux/iommu-helper.h | |||
@@ -14,14 +14,11 @@ static inline unsigned long iommu_device_max_index(unsigned long size, | |||
14 | extern int iommu_is_span_boundary(unsigned int index, unsigned int nr, | 14 | extern int iommu_is_span_boundary(unsigned int index, unsigned int nr, |
15 | unsigned long shift, | 15 | unsigned long shift, |
16 | unsigned long boundary_size); | 16 | unsigned long boundary_size); |
17 | extern void iommu_area_reserve(unsigned long *map, unsigned long i, int len); | ||
18 | extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size, | 17 | extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size, |
19 | unsigned long start, unsigned int nr, | 18 | unsigned long start, unsigned int nr, |
20 | unsigned long shift, | 19 | unsigned long shift, |
21 | unsigned long boundary_size, | 20 | unsigned long boundary_size, |
22 | unsigned long align_mask); | 21 | unsigned long align_mask); |
23 | extern void iommu_area_free(unsigned long *map, unsigned long start, | ||
24 | unsigned int nr); | ||
25 | 22 | ||
26 | extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len, | 23 | extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len, |
27 | unsigned long io_page_size); | 24 | unsigned long io_page_size); |
diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 83aa81297ea3..7129504e053d 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h | |||
@@ -126,11 +126,11 @@ extern int allocate_resource(struct resource *root, struct resource *new, | |||
126 | int adjust_resource(struct resource *res, resource_size_t start, | 126 | int adjust_resource(struct resource *res, resource_size_t start, |
127 | resource_size_t size); | 127 | resource_size_t size); |
128 | resource_size_t resource_alignment(struct resource *res); | 128 | resource_size_t resource_alignment(struct resource *res); |
129 | static inline resource_size_t resource_size(struct resource *res) | 129 | static inline resource_size_t resource_size(const struct resource *res) |
130 | { | 130 | { |
131 | return res->end - res->start + 1; | 131 | return res->end - res->start + 1; |
132 | } | 132 | } |
133 | static inline unsigned long resource_type(struct resource *res) | 133 | static inline unsigned long resource_type(const struct resource *res) |
134 | { | 134 | { |
135 | return res->flags & IORESOURCE_TYPE_BITS; | 135 | return res->flags & IORESOURCE_TYPE_BITS; |
136 | } | 136 | } |
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index e408722a84c7..07baa38bce37 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h | |||
@@ -87,7 +87,7 @@ extern int mq_init_ns(struct ipc_namespace *ns); | |||
87 | /* default values */ | 87 | /* default values */ |
88 | #define DFLT_QUEUESMAX 256 /* max number of message queues */ | 88 | #define DFLT_QUEUESMAX 256 /* max number of message queues */ |
89 | #define DFLT_MSGMAX 10 /* max number of messages in each queue */ | 89 | #define DFLT_MSGMAX 10 /* max number of messages in each queue */ |
90 | #define HARD_MSGMAX (131072/sizeof(void *)) | 90 | #define HARD_MSGMAX (32768*sizeof(void *)/4) |
91 | #define DFLT_MSGSIZEMAX 8192 /* max message size */ | 91 | #define DFLT_MSGSIZEMAX 8192 /* max message size */ |
92 | #else | 92 | #else |
93 | static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; } | 93 | static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; } |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index adc34f2c6eff..c356b6914ffd 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -206,6 +206,8 @@ extern size_t vmcoreinfo_max_size; | |||
206 | 206 | ||
207 | int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, | 207 | int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, |
208 | unsigned long long *crash_size, unsigned long long *crash_base); | 208 | unsigned long long *crash_size, unsigned long long *crash_base); |
209 | int crash_shrink_memory(unsigned long new_size); | ||
210 | size_t crash_get_memory_size(void); | ||
209 | 211 | ||
210 | #else /* !CONFIG_KEXEC */ | 212 | #else /* !CONFIG_KEXEC */ |
211 | struct pt_regs; | 213 | struct pt_regs; |
diff --git a/include/linux/ksm.h b/include/linux/ksm.h index bed5f16ba827..43bdab769fc3 100644 --- a/include/linux/ksm.h +++ b/include/linux/ksm.h | |||
@@ -94,12 +94,6 @@ void ksm_migrate_page(struct page *newpage, struct page *oldpage); | |||
94 | 94 | ||
95 | #else /* !CONFIG_KSM */ | 95 | #else /* !CONFIG_KSM */ |
96 | 96 | ||
97 | static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start, | ||
98 | unsigned long end, int advice, unsigned long *vm_flags) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm) | 97 | static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm) |
104 | { | 98 | { |
105 | return 0; | 99 | return 0; |
@@ -114,6 +108,13 @@ static inline int PageKsm(struct page *page) | |||
114 | return 0; | 108 | return 0; |
115 | } | 109 | } |
116 | 110 | ||
111 | #ifdef CONFIG_MMU | ||
112 | static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start, | ||
113 | unsigned long end, int advice, unsigned long *vm_flags) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | |||
117 | static inline struct page *ksm_might_need_to_copy(struct page *page, | 118 | static inline struct page *ksm_might_need_to_copy(struct page *page, |
118 | struct vm_area_struct *vma, unsigned long address) | 119 | struct vm_area_struct *vma, unsigned long address) |
119 | { | 120 | { |
@@ -140,6 +141,7 @@ static inline int rmap_walk_ksm(struct page *page, int (*rmap_one)(struct page*, | |||
140 | static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage) | 141 | static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage) |
141 | { | 142 | { |
142 | } | 143 | } |
144 | #endif /* CONFIG_MMU */ | ||
143 | #endif /* !CONFIG_KSM */ | 145 | #endif /* !CONFIG_KSM */ |
144 | 146 | ||
145 | #endif /* __LINUX_KSM_H */ | 147 | #endif /* __LINUX_KSM_H */ |
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index bf9213b2db8f..0b46c2068b96 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h | |||
@@ -54,6 +54,11 @@ extern void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru); | |||
54 | extern void mem_cgroup_del_lru(struct page *page); | 54 | extern void mem_cgroup_del_lru(struct page *page); |
55 | extern void mem_cgroup_move_lists(struct page *page, | 55 | extern void mem_cgroup_move_lists(struct page *page, |
56 | enum lru_list from, enum lru_list to); | 56 | enum lru_list from, enum lru_list to); |
57 | |||
58 | /* For coalescing uncharge for reducing memcg' overhead*/ | ||
59 | extern void mem_cgroup_uncharge_start(void); | ||
60 | extern void mem_cgroup_uncharge_end(void); | ||
61 | |||
57 | extern void mem_cgroup_uncharge_page(struct page *page); | 62 | extern void mem_cgroup_uncharge_page(struct page *page); |
58 | extern void mem_cgroup_uncharge_cache_page(struct page *page); | 63 | extern void mem_cgroup_uncharge_cache_page(struct page *page); |
59 | extern int mem_cgroup_shmem_charge_fallback(struct page *page, | 64 | extern int mem_cgroup_shmem_charge_fallback(struct page *page, |
@@ -117,7 +122,7 @@ static inline bool mem_cgroup_disabled(void) | |||
117 | } | 122 | } |
118 | 123 | ||
119 | extern bool mem_cgroup_oom_called(struct task_struct *task); | 124 | extern bool mem_cgroup_oom_called(struct task_struct *task); |
120 | void mem_cgroup_update_mapped_file_stat(struct page *page, int val); | 125 | void mem_cgroup_update_file_mapped(struct page *page, int val); |
121 | unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, | 126 | unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, |
122 | gfp_t gfp_mask, int nid, | 127 | gfp_t gfp_mask, int nid, |
123 | int zid); | 128 | int zid); |
@@ -151,6 +156,14 @@ static inline void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr) | |||
151 | { | 156 | { |
152 | } | 157 | } |
153 | 158 | ||
159 | static inline void mem_cgroup_uncharge_start(void) | ||
160 | { | ||
161 | } | ||
162 | |||
163 | static inline void mem_cgroup_uncharge_end(void) | ||
164 | { | ||
165 | } | ||
166 | |||
154 | static inline void mem_cgroup_uncharge_page(struct page *page) | 167 | static inline void mem_cgroup_uncharge_page(struct page *page) |
155 | { | 168 | { |
156 | } | 169 | } |
@@ -274,7 +287,7 @@ mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) | |||
274 | { | 287 | { |
275 | } | 288 | } |
276 | 289 | ||
277 | static inline void mem_cgroup_update_mapped_file_stat(struct page *page, | 290 | static inline void mem_cgroup_update_file_mapped(struct page *page, |
278 | int val) | 291 | int val) |
279 | { | 292 | { |
280 | } | 293 | } |
diff --git a/include/linux/oom.h b/include/linux/oom.h index 6aac5fe4f6f1..537662315627 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #ifdef __KERNEL__ | 10 | #ifdef __KERNEL__ |
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/nodemask.h> | ||
13 | 14 | ||
14 | struct zonelist; | 15 | struct zonelist; |
15 | struct notifier_block; | 16 | struct notifier_block; |
@@ -26,7 +27,8 @@ enum oom_constraint { | |||
26 | extern int try_set_zone_oom(struct zonelist *zonelist, gfp_t gfp_flags); | 27 | extern int try_set_zone_oom(struct zonelist *zonelist, gfp_t gfp_flags); |
27 | extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags); | 28 | extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags); |
28 | 29 | ||
29 | extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order); | 30 | extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, |
31 | int order, nodemask_t *mask); | ||
30 | extern int register_oom_notifier(struct notifier_block *nb); | 32 | extern int register_oom_notifier(struct notifier_block *nb); |
31 | extern int unregister_oom_notifier(struct notifier_block *nb); | 33 | extern int unregister_oom_notifier(struct notifier_block *nb); |
32 | 34 | ||
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h index 4b938d4f3ac2..b0e4eb126236 100644 --- a/include/linux/page_cgroup.h +++ b/include/linux/page_cgroup.h | |||
@@ -57,6 +57,8 @@ static inline void ClearPageCgroup##uname(struct page_cgroup *pc) \ | |||
57 | static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \ | 57 | static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \ |
58 | { return test_and_clear_bit(PCG_##lname, &pc->flags); } | 58 | { return test_and_clear_bit(PCG_##lname, &pc->flags); } |
59 | 59 | ||
60 | TESTPCGFLAG(Locked, LOCK) | ||
61 | |||
60 | /* Cache flag is set only once (at allocation) */ | 62 | /* Cache flag is set only once (at allocation) */ |
61 | TESTPCGFLAG(Cache, CACHE) | 63 | TESTPCGFLAG(Cache, CACHE) |
62 | CLEARPCGFLAG(Cache, CACHE) | 64 | CLEARPCGFLAG(Cache, CACHE) |
@@ -86,11 +88,6 @@ static inline void lock_page_cgroup(struct page_cgroup *pc) | |||
86 | bit_spin_lock(PCG_LOCK, &pc->flags); | 88 | bit_spin_lock(PCG_LOCK, &pc->flags); |
87 | } | 89 | } |
88 | 90 | ||
89 | static inline int trylock_page_cgroup(struct page_cgroup *pc) | ||
90 | { | ||
91 | return bit_spin_trylock(PCG_LOCK, &pc->flags); | ||
92 | } | ||
93 | |||
94 | static inline void unlock_page_cgroup(struct page_cgroup *pc) | 91 | static inline void unlock_page_cgroup(struct page_cgroup *pc) |
95 | { | 92 | { |
96 | bit_spin_unlock(PCG_LOCK, &pc->flags); | 93 | bit_spin_unlock(PCG_LOCK, &pc->flags); |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 7456d7d87a19..56f2d63a5cbb 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -105,12 +105,7 @@ static inline int ptrace_reparented(struct task_struct *child) | |||
105 | { | 105 | { |
106 | return child->real_parent != child->parent; | 106 | return child->real_parent != child->parent; |
107 | } | 107 | } |
108 | static inline void ptrace_link(struct task_struct *child, | 108 | |
109 | struct task_struct *new_parent) | ||
110 | { | ||
111 | if (unlikely(child->ptrace)) | ||
112 | __ptrace_link(child, new_parent); | ||
113 | } | ||
114 | static inline void ptrace_unlink(struct task_struct *child) | 109 | static inline void ptrace_unlink(struct task_struct *child) |
115 | { | 110 | { |
116 | if (unlikely(child->ptrace)) | 111 | if (unlikely(child->ptrace)) |
@@ -169,9 +164,9 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) | |||
169 | INIT_LIST_HEAD(&child->ptraced); | 164 | INIT_LIST_HEAD(&child->ptraced); |
170 | child->parent = child->real_parent; | 165 | child->parent = child->real_parent; |
171 | child->ptrace = 0; | 166 | child->ptrace = 0; |
172 | if (unlikely(ptrace)) { | 167 | if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) { |
173 | child->ptrace = current->ptrace; | 168 | child->ptrace = current->ptrace; |
174 | ptrace_link(child, current->parent); | 169 | __ptrace_link(child, current->parent); |
175 | } | 170 | } |
176 | } | 171 | } |
177 | 172 | ||
@@ -278,6 +273,18 @@ static inline void user_enable_block_step(struct task_struct *task) | |||
278 | } | 273 | } |
279 | #endif /* arch_has_block_step */ | 274 | #endif /* arch_has_block_step */ |
280 | 275 | ||
276 | #ifdef ARCH_HAS_USER_SINGLE_STEP_INFO | ||
277 | extern void user_single_step_siginfo(struct task_struct *tsk, | ||
278 | struct pt_regs *regs, siginfo_t *info); | ||
279 | #else | ||
280 | static inline void user_single_step_siginfo(struct task_struct *tsk, | ||
281 | struct pt_regs *regs, siginfo_t *info) | ||
282 | { | ||
283 | memset(info, 0, sizeof(*info)); | ||
284 | info->si_signo = SIGTRAP; | ||
285 | } | ||
286 | #endif | ||
287 | |||
281 | #ifndef arch_ptrace_stop_needed | 288 | #ifndef arch_ptrace_stop_needed |
282 | /** | 289 | /** |
283 | * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called | 290 | * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called |
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index a05b4a20768d..c96c1858fe2c 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h | |||
@@ -2051,25 +2051,12 @@ void set_de_name_and_namelen(struct reiserfs_dir_entry *de); | |||
2051 | int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, | 2051 | int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, |
2052 | struct treepath *path, struct reiserfs_dir_entry *de); | 2052 | struct treepath *path, struct reiserfs_dir_entry *de); |
2053 | struct dentry *reiserfs_get_parent(struct dentry *); | 2053 | struct dentry *reiserfs_get_parent(struct dentry *); |
2054 | /* procfs.c */ | ||
2055 | |||
2056 | #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) | ||
2057 | #define REISERFS_PROC_INFO | ||
2058 | #else | ||
2059 | #undef REISERFS_PROC_INFO | ||
2060 | #endif | ||
2061 | 2054 | ||
2055 | #ifdef CONFIG_REISERFS_PROC_INFO | ||
2062 | int reiserfs_proc_info_init(struct super_block *sb); | 2056 | int reiserfs_proc_info_init(struct super_block *sb); |
2063 | int reiserfs_proc_info_done(struct super_block *sb); | 2057 | int reiserfs_proc_info_done(struct super_block *sb); |
2064 | struct proc_dir_entry *reiserfs_proc_register_global(char *name, | ||
2065 | read_proc_t * func); | ||
2066 | void reiserfs_proc_unregister_global(const char *name); | ||
2067 | int reiserfs_proc_info_global_init(void); | 2058 | int reiserfs_proc_info_global_init(void); |
2068 | int reiserfs_proc_info_global_done(void); | 2059 | int reiserfs_proc_info_global_done(void); |
2069 | int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset, | ||
2070 | int count, int *eof, void *data); | ||
2071 | |||
2072 | #if defined( REISERFS_PROC_INFO ) | ||
2073 | 2060 | ||
2074 | #define PROC_EXP( e ) e | 2061 | #define PROC_EXP( e ) e |
2075 | 2062 | ||
@@ -2084,6 +2071,26 @@ int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset, | |||
2084 | PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) ); \ | 2071 | PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) ); \ |
2085 | PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) ) | 2072 | PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) ) |
2086 | #else | 2073 | #else |
2074 | static inline int reiserfs_proc_info_init(struct super_block *sb) | ||
2075 | { | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2079 | static inline int reiserfs_proc_info_done(struct super_block *sb) | ||
2080 | { | ||
2081 | return 0; | ||
2082 | } | ||
2083 | |||
2084 | static inline int reiserfs_proc_info_global_init(void) | ||
2085 | { | ||
2086 | return 0; | ||
2087 | } | ||
2088 | |||
2089 | static inline int reiserfs_proc_info_global_done(void) | ||
2090 | { | ||
2091 | return 0; | ||
2092 | } | ||
2093 | |||
2087 | #define PROC_EXP( e ) | 2094 | #define PROC_EXP( e ) |
2088 | #define VOID_V ( ( void ) 0 ) | 2095 | #define VOID_V ( ( void ) 0 ) |
2089 | #define PROC_INFO_MAX( sb, field, value ) VOID_V | 2096 | #define PROC_INFO_MAX( sb, field, value ) VOID_V |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 5c858f38e81a..244c287a5ac1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1544,6 +1544,14 @@ struct task_struct { | |||
1544 | unsigned long trace_recursion; | 1544 | unsigned long trace_recursion; |
1545 | #endif /* CONFIG_TRACING */ | 1545 | #endif /* CONFIG_TRACING */ |
1546 | unsigned long stack_start; | 1546 | unsigned long stack_start; |
1547 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR /* memcg uses this to do batch job */ | ||
1548 | struct memcg_batch_info { | ||
1549 | int do_batch; /* incremented when batch uncharge started */ | ||
1550 | struct mem_cgroup *memcg; /* target memcg of uncharge */ | ||
1551 | unsigned long bytes; /* uncharged usage */ | ||
1552 | unsigned long memsw_bytes; /* uncharged mem+swap usage */ | ||
1553 | } memcg_batch; | ||
1554 | #endif | ||
1547 | }; | 1555 | }; |
1548 | 1556 | ||
1549 | /* Future-safe accessor for struct task_struct's cpus_allowed. */ | 1557 | /* Future-safe accessor for struct task_struct's cpus_allowed. */ |
@@ -2075,7 +2083,6 @@ extern int kill_proc_info(int, struct siginfo *, pid_t); | |||
2075 | extern int do_notify_parent(struct task_struct *, int); | 2083 | extern int do_notify_parent(struct task_struct *, int); |
2076 | extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); | 2084 | extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); |
2077 | extern void force_sig(int, struct task_struct *); | 2085 | extern void force_sig(int, struct task_struct *); |
2078 | extern void force_sig_specific(int, struct task_struct *); | ||
2079 | extern int send_sig(int, struct task_struct *, int); | 2086 | extern int send_sig(int, struct task_struct *, int); |
2080 | extern void zap_other_threads(struct task_struct *p); | 2087 | extern void zap_other_threads(struct task_struct *p); |
2081 | extern struct sigqueue *sigqueue_alloc(void); | 2088 | extern struct sigqueue *sigqueue_alloc(void); |
@@ -2094,11 +2101,6 @@ static inline int kill_cad_pid(int sig, int priv) | |||
2094 | #define SEND_SIG_PRIV ((struct siginfo *) 1) | 2101 | #define SEND_SIG_PRIV ((struct siginfo *) 1) |
2095 | #define SEND_SIG_FORCED ((struct siginfo *) 2) | 2102 | #define SEND_SIG_FORCED ((struct siginfo *) 2) |
2096 | 2103 | ||
2097 | static inline int is_si_special(const struct siginfo *info) | ||
2098 | { | ||
2099 | return info <= SEND_SIG_FORCED; | ||
2100 | } | ||
2101 | |||
2102 | /* | 2104 | /* |
2103 | * True if we are on the alternate signal stack. | 2105 | * True if we are on the alternate signal stack. |
2104 | */ | 2106 | */ |
diff --git a/include/linux/sem.h b/include/linux/sem.h index 1b191c176bcd..8a4adbef8a0f 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h | |||
@@ -86,6 +86,7 @@ struct task_struct; | |||
86 | struct sem { | 86 | struct sem { |
87 | int semval; /* current value */ | 87 | int semval; /* current value */ |
88 | int sempid; /* pid of last operation */ | 88 | int sempid; /* pid of last operation */ |
89 | struct list_head sem_pending; /* pending single-sop operations */ | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | /* One sem_array data structure for each set of semaphores in the system. */ | 92 | /* One sem_array data structure for each set of semaphores in the system. */ |
@@ -96,11 +97,13 @@ struct sem_array { | |||
96 | struct sem *sem_base; /* ptr to first semaphore in array */ | 97 | struct sem *sem_base; /* ptr to first semaphore in array */ |
97 | struct list_head sem_pending; /* pending operations to be processed */ | 98 | struct list_head sem_pending; /* pending operations to be processed */ |
98 | struct list_head list_id; /* undo requests on this array */ | 99 | struct list_head list_id; /* undo requests on this array */ |
99 | unsigned long sem_nsems; /* no. of semaphores in array */ | 100 | int sem_nsems; /* no. of semaphores in array */ |
101 | int complex_count; /* pending complex operations */ | ||
100 | }; | 102 | }; |
101 | 103 | ||
102 | /* One queue for each sleeping process in the system. */ | 104 | /* One queue for each sleeping process in the system. */ |
103 | struct sem_queue { | 105 | struct sem_queue { |
106 | struct list_head simple_list; /* queue of pending operations */ | ||
104 | struct list_head list; /* queue of pending operations */ | 107 | struct list_head list; /* queue of pending operations */ |
105 | struct task_struct *sleeper; /* this process */ | 108 | struct task_struct *sleeper; /* this process */ |
106 | struct sem_undo *undo; /* undo structure */ | 109 | struct sem_undo *undo; /* undo structure */ |
diff --git a/include/linux/sm501-regs.h b/include/linux/sm501-regs.h index d53642d2d899..67ed2c542831 100644 --- a/include/linux/sm501-regs.h +++ b/include/linux/sm501-regs.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11) | 31 | #define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11) |
32 | #define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15) | 32 | #define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15) |
33 | 33 | ||
34 | #define SM501_SYSCTRL_2D_ENGINE_STATUS (1<<19) | ||
35 | |||
34 | /* miscellaneous control */ | 36 | /* miscellaneous control */ |
35 | 37 | ||
36 | #define SM501_MISC_CONTROL (0x000004) | 38 | #define SM501_MISC_CONTROL (0x000004) |
diff --git a/include/linux/timb_gpio.h b/include/linux/timb_gpio.h new file mode 100644 index 000000000000..ce456eaae861 --- /dev/null +++ b/include/linux/timb_gpio.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * timb_gpio.h timberdale FPGA GPIO driver, platform data definition | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | #ifndef _LINUX_TIMB_GPIO_H | ||
20 | #define _LINUX_TIMB_GPIO_H | ||
21 | |||
22 | /** | ||
23 | * struct timbgpio_platform_data - Platform data of the Timberdale GPIO driver | ||
24 | * @gpio_base The number of the first GPIO pin, set to -1 for | ||
25 | * dynamic number allocation. | ||
26 | * @nr_pins Number of pins that is supported by the hardware (1-32) | ||
27 | * @irq_base If IRQ is supported by the hardware, this is the base | ||
28 | * number of IRQ:s. One IRQ per pin will be used. Set to | ||
29 | * -1 if IRQ:s is not supported. | ||
30 | */ | ||
31 | struct timbgpio_platform_data { | ||
32 | int gpio_base; | ||
33 | int nr_pins; | ||
34 | int irq_base; | ||
35 | }; | ||
36 | |||
37 | #endif | ||
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 1eb44a924e56..10db0102a890 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h | |||
@@ -134,6 +134,13 @@ static inline __must_check int tracehook_report_syscall_entry( | |||
134 | */ | 134 | */ |
135 | static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) | 135 | static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) |
136 | { | 136 | { |
137 | if (step) { | ||
138 | siginfo_t info; | ||
139 | user_single_step_siginfo(current, regs, &info); | ||
140 | force_sig_info(SIGTRAP, &info, current); | ||
141 | return; | ||
142 | } | ||
143 | |||
137 | ptrace_report_syscall(regs); | 144 | ptrace_report_syscall(regs); |
138 | } | 145 | } |
139 | 146 | ||
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 32b92298fd79..d4962a782b8a 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h | |||
@@ -294,6 +294,7 @@ struct v4l2_pix_format { | |||
294 | 294 | ||
295 | /* Grey formats */ | 295 | /* Grey formats */ |
296 | #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ | 296 | #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ |
297 | #define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ | ||
297 | #define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ | 298 | #define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ |
298 | 299 | ||
299 | /* Palette formats */ | 300 | /* Palette formats */ |
@@ -329,7 +330,11 @@ struct v4l2_pix_format { | |||
329 | #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ | 330 | #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ |
330 | #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ | 331 | #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ |
331 | #define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ | 332 | #define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ |
332 | #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */ | 333 | #define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ |
334 | #define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ | ||
335 | #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ | ||
336 | #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ | ||
337 | #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ | ||
333 | /* 10bit raw bayer DPCM compressed to 8 bits */ | 338 | /* 10bit raw bayer DPCM compressed to 8 bits */ |
334 | #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') | 339 | #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') |
335 | /* | 340 | /* |
@@ -732,6 +737,99 @@ struct v4l2_standard { | |||
732 | }; | 737 | }; |
733 | 738 | ||
734 | /* | 739 | /* |
740 | * V I D E O T I M I N G S D V P R E S E T | ||
741 | */ | ||
742 | struct v4l2_dv_preset { | ||
743 | __u32 preset; | ||
744 | __u32 reserved[4]; | ||
745 | }; | ||
746 | |||
747 | /* | ||
748 | * D V P R E S E T S E N U M E R A T I O N | ||
749 | */ | ||
750 | struct v4l2_dv_enum_preset { | ||
751 | __u32 index; | ||
752 | __u32 preset; | ||
753 | __u8 name[32]; /* Name of the preset timing */ | ||
754 | __u32 width; | ||
755 | __u32 height; | ||
756 | __u32 reserved[4]; | ||
757 | }; | ||
758 | |||
759 | /* | ||
760 | * D V P R E S E T V A L U E S | ||
761 | */ | ||
762 | #define V4L2_DV_INVALID 0 | ||
763 | #define V4L2_DV_480P59_94 1 /* BT.1362 */ | ||
764 | #define V4L2_DV_576P50 2 /* BT.1362 */ | ||
765 | #define V4L2_DV_720P24 3 /* SMPTE 296M */ | ||
766 | #define V4L2_DV_720P25 4 /* SMPTE 296M */ | ||
767 | #define V4L2_DV_720P30 5 /* SMPTE 296M */ | ||
768 | #define V4L2_DV_720P50 6 /* SMPTE 296M */ | ||
769 | #define V4L2_DV_720P59_94 7 /* SMPTE 274M */ | ||
770 | #define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ | ||
771 | #define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ | ||
772 | #define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ | ||
773 | #define V4L2_DV_1080I25 11 /* BT.1120 */ | ||
774 | #define V4L2_DV_1080I50 12 /* SMPTE 296M */ | ||
775 | #define V4L2_DV_1080I60 13 /* SMPTE 296M */ | ||
776 | #define V4L2_DV_1080P24 14 /* SMPTE 296M */ | ||
777 | #define V4L2_DV_1080P25 15 /* SMPTE 296M */ | ||
778 | #define V4L2_DV_1080P30 16 /* SMPTE 296M */ | ||
779 | #define V4L2_DV_1080P50 17 /* BT.1120 */ | ||
780 | #define V4L2_DV_1080P60 18 /* BT.1120 */ | ||
781 | |||
782 | /* | ||
783 | * D V B T T I M I N G S | ||
784 | */ | ||
785 | |||
786 | /* BT.656/BT.1120 timing data */ | ||
787 | struct v4l2_bt_timings { | ||
788 | __u32 width; /* width in pixels */ | ||
789 | __u32 height; /* height in lines */ | ||
790 | __u32 interlaced; /* Interlaced or progressive */ | ||
791 | __u32 polarities; /* Positive or negative polarity */ | ||
792 | __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ | ||
793 | __u32 hfrontporch; /* Horizpontal front porch in pixels */ | ||
794 | __u32 hsync; /* Horizontal Sync length in pixels */ | ||
795 | __u32 hbackporch; /* Horizontal back porch in pixels */ | ||
796 | __u32 vfrontporch; /* Vertical front porch in pixels */ | ||
797 | __u32 vsync; /* Vertical Sync length in lines */ | ||
798 | __u32 vbackporch; /* Vertical back porch in lines */ | ||
799 | __u32 il_vfrontporch; /* Vertical front porch for bottom field of | ||
800 | * interlaced field formats | ||
801 | */ | ||
802 | __u32 il_vsync; /* Vertical sync length for bottom field of | ||
803 | * interlaced field formats | ||
804 | */ | ||
805 | __u32 il_vbackporch; /* Vertical back porch for bottom field of | ||
806 | * interlaced field formats | ||
807 | */ | ||
808 | __u32 reserved[16]; | ||
809 | } __attribute__ ((packed)); | ||
810 | |||
811 | /* Interlaced or progressive format */ | ||
812 | #define V4L2_DV_PROGRESSIVE 0 | ||
813 | #define V4L2_DV_INTERLACED 1 | ||
814 | |||
815 | /* Polarities. If bit is not set, it is assumed to be negative polarity */ | ||
816 | #define V4L2_DV_VSYNC_POS_POL 0x00000001 | ||
817 | #define V4L2_DV_HSYNC_POS_POL 0x00000002 | ||
818 | |||
819 | |||
820 | /* DV timings */ | ||
821 | struct v4l2_dv_timings { | ||
822 | __u32 type; | ||
823 | union { | ||
824 | struct v4l2_bt_timings bt; | ||
825 | __u32 reserved[32]; | ||
826 | }; | ||
827 | } __attribute__ ((packed)); | ||
828 | |||
829 | /* Values for the type field */ | ||
830 | #define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ | ||
831 | |||
832 | /* | ||
735 | * V I D E O I N P U T S | 833 | * V I D E O I N P U T S |
736 | */ | 834 | */ |
737 | struct v4l2_input { | 835 | struct v4l2_input { |
@@ -742,7 +840,8 @@ struct v4l2_input { | |||
742 | __u32 tuner; /* Associated tuner */ | 840 | __u32 tuner; /* Associated tuner */ |
743 | v4l2_std_id std; | 841 | v4l2_std_id std; |
744 | __u32 status; | 842 | __u32 status; |
745 | __u32 reserved[4]; | 843 | __u32 capabilities; |
844 | __u32 reserved[3]; | ||
746 | }; | 845 | }; |
747 | 846 | ||
748 | /* Values for the 'type' field */ | 847 | /* Values for the 'type' field */ |
@@ -773,6 +872,11 @@ struct v4l2_input { | |||
773 | #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ | 872 | #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ |
774 | #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ | 873 | #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ |
775 | 874 | ||
875 | /* capabilities flags */ | ||
876 | #define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ | ||
877 | #define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ | ||
878 | #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ | ||
879 | |||
776 | /* | 880 | /* |
777 | * V I D E O O U T P U T S | 881 | * V I D E O O U T P U T S |
778 | */ | 882 | */ |
@@ -783,13 +887,19 @@ struct v4l2_output { | |||
783 | __u32 audioset; /* Associated audios (bitfield) */ | 887 | __u32 audioset; /* Associated audios (bitfield) */ |
784 | __u32 modulator; /* Associated modulator */ | 888 | __u32 modulator; /* Associated modulator */ |
785 | v4l2_std_id std; | 889 | v4l2_std_id std; |
786 | __u32 reserved[4]; | 890 | __u32 capabilities; |
891 | __u32 reserved[3]; | ||
787 | }; | 892 | }; |
788 | /* Values for the 'type' field */ | 893 | /* Values for the 'type' field */ |
789 | #define V4L2_OUTPUT_TYPE_MODULATOR 1 | 894 | #define V4L2_OUTPUT_TYPE_MODULATOR 1 |
790 | #define V4L2_OUTPUT_TYPE_ANALOG 2 | 895 | #define V4L2_OUTPUT_TYPE_ANALOG 2 |
791 | #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 | 896 | #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 |
792 | 897 | ||
898 | /* capabilities flags */ | ||
899 | #define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ | ||
900 | #define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ | ||
901 | #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ | ||
902 | |||
793 | /* | 903 | /* |
794 | * C O N T R O L S | 904 | * C O N T R O L S |
795 | */ | 905 | */ |
@@ -1624,6 +1734,13 @@ struct v4l2_dbg_chip_ident { | |||
1624 | #endif | 1734 | #endif |
1625 | 1735 | ||
1626 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) | 1736 | #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) |
1737 | #define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) | ||
1738 | #define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) | ||
1739 | #define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) | ||
1740 | #define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) | ||
1741 | #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) | ||
1742 | #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) | ||
1743 | |||
1627 | /* Reminder: when adding new ioctls please add support for them to | 1744 | /* Reminder: when adding new ioctls please add support for them to |
1628 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ | 1745 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ |
1629 | 1746 | ||
diff --git a/include/media/ir-common.h b/include/media/ir-common.h index e41a99ee353e..2c6af24b905e 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h | |||
@@ -26,26 +26,7 @@ | |||
26 | #include <linux/input.h> | 26 | #include <linux/input.h> |
27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/spinlock.h> | 29 | #include <media/ir-core.h> |
30 | |||
31 | extern int media_ir_debug; /* media_ir_debug level (0,1,2) */ | ||
32 | #define IR_dprintk(level, fmt, arg...) if (media_ir_debug >= level) \ | ||
33 | printk(KERN_DEBUG "%s: " fmt , __func__, ## arg) | ||
34 | |||
35 | #define IR_TYPE_RC5 1 | ||
36 | #define IR_TYPE_PD 2 /* Pulse distance encoded IR */ | ||
37 | #define IR_TYPE_OTHER 99 | ||
38 | |||
39 | struct ir_scancode { | ||
40 | u16 scancode; | ||
41 | u32 keycode; | ||
42 | }; | ||
43 | |||
44 | struct ir_scancode_table { | ||
45 | struct ir_scancode *scan; | ||
46 | int size; | ||
47 | spinlock_t lock; | ||
48 | }; | ||
49 | 30 | ||
50 | #define RC5_START(x) (((x)>>12)&3) | 31 | #define RC5_START(x) (((x)>>12)&3) |
51 | #define RC5_TOGGLE(x) (((x)>>11)&1) | 32 | #define RC5_TOGGLE(x) (((x)>>11)&1) |
@@ -56,8 +37,6 @@ struct ir_input_state { | |||
56 | /* configuration */ | 37 | /* configuration */ |
57 | int ir_type; | 38 | int ir_type; |
58 | 39 | ||
59 | struct ir_scancode_table keytable; | ||
60 | |||
61 | /* key info */ | 40 | /* key info */ |
62 | u32 ir_key; /* ir scancode */ | 41 | u32 ir_key; /* ir scancode */ |
63 | u32 keycode; /* linux key code */ | 42 | u32 keycode; /* linux key code */ |
@@ -105,7 +84,7 @@ struct card_ir { | |||
105 | /* Routines from ir-functions.c */ | 84 | /* Routines from ir-functions.c */ |
106 | 85 | ||
107 | int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, | 86 | int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, |
108 | int ir_type, struct ir_scancode_table *ir_codes); | 87 | int ir_type); |
109 | void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir); | 88 | void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir); |
110 | void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, | 89 | void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, |
111 | u32 ir_key); | 90 | u32 ir_key); |
@@ -118,19 +97,6 @@ u32 ir_rc5_decode(unsigned int code); | |||
118 | void ir_rc5_timer_end(unsigned long data); | 97 | void ir_rc5_timer_end(unsigned long data); |
119 | void ir_rc5_timer_keyup(unsigned long data); | 98 | void ir_rc5_timer_keyup(unsigned long data); |
120 | 99 | ||
121 | /* Routines from ir-keytable.c */ | ||
122 | |||
123 | u32 ir_g_keycode_from_table(struct input_dev *input_dev, | ||
124 | u32 scancode); | ||
125 | |||
126 | int ir_set_keycode_table(struct input_dev *input_dev, | ||
127 | struct ir_scancode_table *rc_tab); | ||
128 | |||
129 | int ir_roundup_tablesize(int n_elems); | ||
130 | int ir_copy_table(struct ir_scancode_table *destin, | ||
131 | const struct ir_scancode_table *origin); | ||
132 | void ir_input_free(struct input_dev *input_dev); | ||
133 | |||
134 | /* scancode->keycode map tables from ir-keymaps.c */ | 100 | /* scancode->keycode map tables from ir-keymaps.c */ |
135 | 101 | ||
136 | extern struct ir_scancode_table ir_codes_empty_table; | 102 | extern struct ir_scancode_table ir_codes_empty_table; |
@@ -195,4 +161,5 @@ extern struct ir_scancode_table ir_codes_evga_indtube_table; | |||
195 | extern struct ir_scancode_table ir_codes_terratec_cinergy_xs_table; | 161 | extern struct ir_scancode_table ir_codes_terratec_cinergy_xs_table; |
196 | extern struct ir_scancode_table ir_codes_videomate_s350_table; | 162 | extern struct ir_scancode_table ir_codes_videomate_s350_table; |
197 | extern struct ir_scancode_table ir_codes_gadmei_rm008z_table; | 163 | extern struct ir_scancode_table ir_codes_gadmei_rm008z_table; |
164 | extern struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table; | ||
198 | #endif | 165 | #endif |
diff --git a/include/media/ir-core.h b/include/media/ir-core.h new file mode 100644 index 000000000000..299d201e1339 --- /dev/null +++ b/include/media/ir-core.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Remote Controller core header | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation version 2 of the License. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef _IR_CORE | ||
15 | #define _IR_CORE | ||
16 | |||
17 | #include <linux/input.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | extern int ir_core_debug; | ||
21 | #define IR_dprintk(level, fmt, arg...) if (ir_core_debug >= level) \ | ||
22 | printk(KERN_DEBUG "%s: " fmt , __func__, ## arg) | ||
23 | |||
24 | enum ir_type { | ||
25 | IR_TYPE_UNKNOWN = 0, | ||
26 | IR_TYPE_RC5 = 1, | ||
27 | IR_TYPE_PD = 2, /* Pulse distance encoded IR */ | ||
28 | IR_TYPE_NEC = 3, | ||
29 | IR_TYPE_OTHER = 99, | ||
30 | }; | ||
31 | |||
32 | struct ir_scancode { | ||
33 | u16 scancode; | ||
34 | u32 keycode; | ||
35 | }; | ||
36 | |||
37 | struct ir_scancode_table { | ||
38 | struct ir_scancode *scan; | ||
39 | int size; | ||
40 | enum ir_type ir_type; | ||
41 | spinlock_t lock; | ||
42 | }; | ||
43 | |||
44 | struct ir_input_dev { | ||
45 | struct input_dev *dev; | ||
46 | struct ir_scancode_table rc_tab; | ||
47 | }; | ||
48 | |||
49 | /* Routines from ir-keytable.c */ | ||
50 | |||
51 | u32 ir_g_keycode_from_table(struct input_dev *input_dev, | ||
52 | u32 scancode); | ||
53 | |||
54 | int ir_set_keycode_table(struct input_dev *input_dev, | ||
55 | struct ir_scancode_table *rc_tab); | ||
56 | |||
57 | int ir_roundup_tablesize(int n_elems); | ||
58 | int ir_input_register(struct input_dev *dev, | ||
59 | struct ir_scancode_table *ir_codes); | ||
60 | void ir_input_unregister(struct input_dev *input_dev); | ||
61 | |||
62 | #endif | ||
diff --git a/include/media/mt9t112.h b/include/media/mt9t112.h new file mode 100644 index 000000000000..a43c74ab05ec --- /dev/null +++ b/include/media/mt9t112.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* mt9t112 Camera | ||
2 | * | ||
3 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
4 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __MT9T112_H__ | ||
12 | #define __MT9T112_H__ | ||
13 | |||
14 | #define MT9T112_FLAG_PCLK_RISING_EDGE (1 << 0) | ||
15 | #define MT9T112_FLAG_DATAWIDTH_8 (1 << 1) /* default width is 10 */ | ||
16 | |||
17 | struct mt9t112_pll_divider { | ||
18 | u8 m, n; | ||
19 | u8 p1, p2, p3, p4, p5, p6, p7; | ||
20 | }; | ||
21 | |||
22 | /* | ||
23 | * mt9t112 camera info | ||
24 | */ | ||
25 | struct mt9t112_camera_info { | ||
26 | u32 flags; | ||
27 | struct mt9t112_pll_divider divider; | ||
28 | }; | ||
29 | |||
30 | #endif /* __MT9T112_H__ */ | ||
diff --git a/include/media/ov772x.h b/include/media/ov772x.h index 30d9629198ef..14c77efd6a85 100644 --- a/include/media/ov772x.h +++ b/include/media/ov772x.h | |||
@@ -1,4 +1,5 @@ | |||
1 | /* ov772x Camera | 1 | /* |
2 | * ov772x Camera | ||
2 | * | 3 | * |
3 | * Copyright (C) 2008 Renesas Solutions Corp. | 4 | * Copyright (C) 2008 Renesas Solutions Corp. |
4 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | 5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> |
@@ -54,7 +55,6 @@ struct ov772x_edge_ctrl { | |||
54 | struct ov772x_camera_info { | 55 | struct ov772x_camera_info { |
55 | unsigned long buswidth; | 56 | unsigned long buswidth; |
56 | unsigned long flags; | 57 | unsigned long flags; |
57 | struct soc_camera_link link; | ||
58 | struct ov772x_edge_ctrl edgectrl; | 58 | struct ov772x_edge_ctrl edgectrl; |
59 | }; | 59 | }; |
60 | 60 | ||
diff --git a/include/media/rj54n1cb0c.h b/include/media/rj54n1cb0c.h new file mode 100644 index 000000000000..8ae3288ae925 --- /dev/null +++ b/include/media/rj54n1cb0c.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * RJ54N1CB0C Private data | ||
3 | * | ||
4 | * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __RJ54N1CB0C_H__ | ||
12 | #define __RJ54N1CB0C_H__ | ||
13 | |||
14 | struct rj54n1_pdata { | ||
15 | unsigned int mclk_freq; | ||
16 | bool ioctl_high; | ||
17 | }; | ||
18 | |||
19 | #endif | ||
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index eed5fccc83f3..4aeff96ff7d8 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h | |||
@@ -108,8 +108,6 @@ struct saa7146_fh { | |||
108 | 108 | ||
109 | struct saa7146_vv | 109 | struct saa7146_vv |
110 | { | 110 | { |
111 | int vbi_minor; | ||
112 | |||
113 | /* vbi capture */ | 111 | /* vbi capture */ |
114 | struct saa7146_dmaqueue vbi_q; | 112 | struct saa7146_dmaqueue vbi_q; |
115 | /* vbi workaround interrupt queue */ | 113 | /* vbi workaround interrupt queue */ |
@@ -117,8 +115,6 @@ struct saa7146_vv | |||
117 | int vbi_fieldcount; | 115 | int vbi_fieldcount; |
118 | struct saa7146_fh *vbi_streaming; | 116 | struct saa7146_fh *vbi_streaming; |
119 | 117 | ||
120 | int video_minor; | ||
121 | |||
122 | int video_status; | 118 | int video_status; |
123 | struct saa7146_fh *video_fh; | 119 | struct saa7146_fh *video_fh; |
124 | 120 | ||
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h index 0f3524cff435..b67747836878 100644 --- a/include/media/sh_mobile_ceu.h +++ b/include/media/sh_mobile_ceu.h | |||
@@ -3,6 +3,8 @@ | |||
3 | 3 | ||
4 | #define SH_CEU_FLAG_USE_8BIT_BUS (1 << 0) /* use 8bit bus width */ | 4 | #define SH_CEU_FLAG_USE_8BIT_BUS (1 << 0) /* use 8bit bus width */ |
5 | #define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */ | 5 | #define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */ |
6 | #define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */ | ||
7 | #define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */ | ||
6 | 8 | ||
7 | struct sh_mobile_ceu_info { | 9 | struct sh_mobile_ceu_info { |
8 | unsigned long flags; | 10 | unsigned long flags; |
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 3d74e60032dd..dcc5b86bcb6c 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h | |||
@@ -24,18 +24,13 @@ struct soc_camera_device { | |||
24 | struct device *pdev; /* Platform device */ | 24 | struct device *pdev; /* Platform device */ |
25 | s32 user_width; | 25 | s32 user_width; |
26 | s32 user_height; | 26 | s32 user_height; |
27 | unsigned short width_min; | 27 | enum v4l2_colorspace colorspace; |
28 | unsigned short height_min; | ||
29 | unsigned short y_skip_top; /* Lines to skip at the top */ | ||
30 | unsigned char iface; /* Host number */ | 28 | unsigned char iface; /* Host number */ |
31 | unsigned char devnum; /* Device number per host */ | 29 | unsigned char devnum; /* Device number per host */ |
32 | unsigned char buswidth; /* See comment in .c */ | ||
33 | struct soc_camera_sense *sense; /* See comment in struct definition */ | 30 | struct soc_camera_sense *sense; /* See comment in struct definition */ |
34 | struct soc_camera_ops *ops; | 31 | struct soc_camera_ops *ops; |
35 | struct video_device *vdev; | 32 | struct video_device *vdev; |
36 | const struct soc_camera_data_format *current_fmt; | 33 | const struct soc_camera_format_xlate *current_fmt; |
37 | const struct soc_camera_data_format *formats; | ||
38 | int num_formats; | ||
39 | struct soc_camera_format_xlate *user_formats; | 34 | struct soc_camera_format_xlate *user_formats; |
40 | int num_user_formats; | 35 | int num_user_formats; |
41 | enum v4l2_field field; /* Preserve field over close() */ | 36 | enum v4l2_field field; /* Preserve field over close() */ |
@@ -107,6 +102,8 @@ struct soc_camera_link { | |||
107 | int i2c_adapter_id; | 102 | int i2c_adapter_id; |
108 | struct i2c_board_info *board_info; | 103 | struct i2c_board_info *board_info; |
109 | const char *module_name; | 104 | const char *module_name; |
105 | void *priv; | ||
106 | |||
110 | /* | 107 | /* |
111 | * For non-I2C devices platform platform has to provide methods to | 108 | * For non-I2C devices platform platform has to provide methods to |
112 | * add a device to the system and to remove | 109 | * add a device to the system and to remove |
@@ -162,23 +159,13 @@ static inline struct v4l2_subdev *soc_camera_to_subdev( | |||
162 | int soc_camera_host_register(struct soc_camera_host *ici); | 159 | int soc_camera_host_register(struct soc_camera_host *ici); |
163 | void soc_camera_host_unregister(struct soc_camera_host *ici); | 160 | void soc_camera_host_unregister(struct soc_camera_host *ici); |
164 | 161 | ||
165 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | ||
166 | struct soc_camera_device *icd, unsigned int fourcc); | ||
167 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 162 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
168 | struct soc_camera_device *icd, unsigned int fourcc); | 163 | struct soc_camera_device *icd, unsigned int fourcc); |
169 | 164 | ||
170 | struct soc_camera_data_format { | ||
171 | const char *name; | ||
172 | unsigned int depth; | ||
173 | __u32 fourcc; | ||
174 | enum v4l2_colorspace colorspace; | ||
175 | }; | ||
176 | |||
177 | /** | 165 | /** |
178 | * struct soc_camera_format_xlate - match between host and sensor formats | 166 | * struct soc_camera_format_xlate - match between host and sensor formats |
179 | * @cam_fmt: sensor format provided by the sensor | 167 | * @code: code of a sensor provided format |
180 | * @host_fmt: host format after host translation from cam_fmt | 168 | * @host_fmt: host format after host translation from code |
181 | * @buswidth: bus width for this format | ||
182 | * | 169 | * |
183 | * Host and sensor translation structure. Used in table of host and sensor | 170 | * Host and sensor translation structure. Used in table of host and sensor |
184 | * formats matchings in soc_camera_device. A host can override the generic list | 171 | * formats matchings in soc_camera_device. A host can override the generic list |
@@ -186,9 +173,8 @@ struct soc_camera_data_format { | |||
186 | * format setup. | 173 | * format setup. |
187 | */ | 174 | */ |
188 | struct soc_camera_format_xlate { | 175 | struct soc_camera_format_xlate { |
189 | const struct soc_camera_data_format *cam_fmt; | 176 | enum v4l2_mbus_pixelcode code; |
190 | const struct soc_camera_data_format *host_fmt; | 177 | const struct soc_mbus_pixelfmt *host_fmt; |
191 | unsigned char buswidth; | ||
192 | }; | 178 | }; |
193 | 179 | ||
194 | struct soc_camera_ops { | 180 | struct soc_camera_ops { |
diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h index bb70401b8141..0ecefe227b76 100644 --- a/include/media/soc_camera_platform.h +++ b/include/media/soc_camera_platform.h | |||
@@ -19,11 +19,10 @@ struct device; | |||
19 | struct soc_camera_platform_info { | 19 | struct soc_camera_platform_info { |
20 | const char *format_name; | 20 | const char *format_name; |
21 | unsigned long format_depth; | 21 | unsigned long format_depth; |
22 | struct v4l2_pix_format format; | 22 | struct v4l2_mbus_framefmt format; |
23 | unsigned long bus_param; | 23 | unsigned long bus_param; |
24 | struct device *dev; | 24 | struct device *dev; |
25 | int (*set_capture)(struct soc_camera_platform_info *info, int enable); | 25 | int (*set_capture)(struct soc_camera_platform_info *info, int enable); |
26 | struct soc_camera_link link; | ||
27 | }; | 26 | }; |
28 | 27 | ||
29 | #endif /* __SOC_CAMERA_H__ */ | 28 | #endif /* __SOC_CAMERA_H__ */ |
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h new file mode 100644 index 000000000000..037cd7be001e --- /dev/null +++ b/include/media/soc_mediabus.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * SoC-camera Media Bus API extensions | ||
3 | * | ||
4 | * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef SOC_MEDIABUS_H | ||
12 | #define SOC_MEDIABUS_H | ||
13 | |||
14 | #include <linux/videodev2.h> | ||
15 | |||
16 | #include <media/v4l2-mediabus.h> | ||
17 | |||
18 | /** | ||
19 | * enum soc_mbus_packing - data packing types on the media-bus | ||
20 | * @SOC_MBUS_PACKING_NONE: no packing, bit-for-bit transfer to RAM | ||
21 | * @SOC_MBUS_PACKING_2X8_PADHI: 16 bits transferred in 2 8-bit samples, in the | ||
22 | * possibly incomplete byte high bits are padding | ||
23 | * @SOC_MBUS_PACKING_2X8_PADLO: as above, but low bits are padding | ||
24 | * @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended | ||
25 | * to 16 bits | ||
26 | */ | ||
27 | enum soc_mbus_packing { | ||
28 | SOC_MBUS_PACKING_NONE, | ||
29 | SOC_MBUS_PACKING_2X8_PADHI, | ||
30 | SOC_MBUS_PACKING_2X8_PADLO, | ||
31 | SOC_MBUS_PACKING_EXTEND16, | ||
32 | }; | ||
33 | |||
34 | /** | ||
35 | * enum soc_mbus_order - sample order on the media bus | ||
36 | * @SOC_MBUS_ORDER_LE: least significant sample first | ||
37 | * @SOC_MBUS_ORDER_BE: most significant sample first | ||
38 | */ | ||
39 | enum soc_mbus_order { | ||
40 | SOC_MBUS_ORDER_LE, | ||
41 | SOC_MBUS_ORDER_BE, | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * struct soc_mbus_pixelfmt - Data format on the media bus | ||
46 | * @name: Name of the format | ||
47 | * @fourcc: Fourcc code, that will be obtained if the data is | ||
48 | * stored in memory in the following way: | ||
49 | * @packing: Type of sample-packing, that has to be used | ||
50 | * @order: Sample order when storing in memory | ||
51 | * @bits_per_sample: How many bits the bridge has to sample | ||
52 | */ | ||
53 | struct soc_mbus_pixelfmt { | ||
54 | const char *name; | ||
55 | u32 fourcc; | ||
56 | enum soc_mbus_packing packing; | ||
57 | enum soc_mbus_order order; | ||
58 | u8 bits_per_sample; | ||
59 | }; | ||
60 | |||
61 | const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | ||
62 | enum v4l2_mbus_pixelcode code); | ||
63 | s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); | ||
64 | |||
65 | #endif | ||
diff --git a/include/media/tw9910.h b/include/media/tw9910.h index 73231e7880d8..5e2895a05e6b 100644 --- a/include/media/tw9910.h +++ b/include/media/tw9910.h | |||
@@ -32,7 +32,6 @@ enum tw9910_mpout_pin { | |||
32 | struct tw9910_video_info { | 32 | struct tw9910_video_info { |
33 | unsigned long buswidth; | 33 | unsigned long buswidth; |
34 | enum tw9910_mpout_pin mpout; | 34 | enum tw9910_mpout_pin mpout; |
35 | struct soc_camera_link link; | ||
36 | }; | 35 | }; |
37 | 36 | ||
38 | 37 | ||
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 91942dbe64e3..6cc107d198a0 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h | |||
@@ -267,6 +267,8 @@ enum { | |||
267 | V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */ | 267 | V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */ |
268 | V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */ | 268 | V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */ |
269 | V4L2_IDENT_MT9T031 = 45020, | 269 | V4L2_IDENT_MT9T031 = 45020, |
270 | V4L2_IDENT_MT9T111 = 45021, | ||
271 | V4L2_IDENT_MT9T112 = 45022, | ||
270 | V4L2_IDENT_MT9V111 = 45031, | 272 | V4L2_IDENT_MT9V111 = 45031, |
271 | V4L2_IDENT_MT9V112 = 45032, | 273 | V4L2_IDENT_MT9V112 = 45032, |
272 | 274 | ||
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 1c25b10da34b..1c7b259f341c 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h | |||
@@ -212,5 +212,5 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin, | |||
212 | unsigned int *h, unsigned int hmin, | 212 | unsigned int *h, unsigned int hmin, |
213 | unsigned int hmax, unsigned int halign, | 213 | unsigned int hmax, unsigned int halign, |
214 | unsigned int salign); | 214 | unsigned int salign); |
215 | 215 | int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info); | |
216 | #endif /* V4L2_COMMON_H_ */ | 216 | #endif /* V4L2_COMMON_H_ */ |
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 73c9867d744c..2dee93892ea2 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h | |||
@@ -28,10 +28,10 @@ struct v4l2_ioctl_callbacks; | |||
28 | struct video_device; | 28 | struct video_device; |
29 | struct v4l2_device; | 29 | struct v4l2_device; |
30 | 30 | ||
31 | /* Flag to mark the video_device struct as unregistered. | 31 | /* Flag to mark the video_device struct as registered. |
32 | Drivers can set this flag if they want to block all future | 32 | Drivers can clear this flag if they want to block all future |
33 | device access. It is set by video_unregister_device. */ | 33 | device access. It is cleared by video_unregister_device. */ |
34 | #define V4L2_FL_UNREGISTERED (0) | 34 | #define V4L2_FL_REGISTERED (0) |
35 | 35 | ||
36 | struct v4l2_file_operations { | 36 | struct v4l2_file_operations { |
37 | struct module *owner; | 37 | struct module *owner; |
@@ -96,9 +96,7 @@ struct video_device | |||
96 | /* Register video devices. Note that if video_register_device fails, | 96 | /* Register video devices. Note that if video_register_device fails, |
97 | the release() callback of the video_device structure is *not* called, so | 97 | the release() callback of the video_device structure is *not* called, so |
98 | the caller is responsible for freeing any data. Usually that means that | 98 | the caller is responsible for freeing any data. Usually that means that |
99 | you call video_device_release() on failure. | 99 | you call video_device_release() on failure. */ |
100 | |||
101 | Also note that vdev->minor is set to -1 if the registration failed. */ | ||
102 | int __must_check video_register_device(struct video_device *vdev, int type, int nr); | 100 | int __must_check video_register_device(struct video_device *vdev, int type, int nr); |
103 | 101 | ||
104 | /* Same as video_register_device, but no warning is issued if the desired | 102 | /* Same as video_register_device, but no warning is issued if the desired |
@@ -106,7 +104,7 @@ int __must_check video_register_device(struct video_device *vdev, int type, int | |||
106 | int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr); | 104 | int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr); |
107 | 105 | ||
108 | /* Unregister video devices. Will do nothing if vdev == NULL or | 106 | /* Unregister video devices. Will do nothing if vdev == NULL or |
109 | vdev->minor < 0. */ | 107 | video_is_registered() returns false. */ |
110 | void video_unregister_device(struct video_device *vdev); | 108 | void video_unregister_device(struct video_device *vdev); |
111 | 109 | ||
112 | /* helper functions to alloc/release struct video_device, the | 110 | /* helper functions to alloc/release struct video_device, the |
@@ -141,9 +139,14 @@ static inline void *video_drvdata(struct file *file) | |||
141 | return video_get_drvdata(video_devdata(file)); | 139 | return video_get_drvdata(video_devdata(file)); |
142 | } | 140 | } |
143 | 141 | ||
144 | static inline int video_is_unregistered(struct video_device *vdev) | 142 | static inline const char *video_device_node_name(struct video_device *vdev) |
143 | { | ||
144 | return dev_name(&vdev->dev); | ||
145 | } | ||
146 | |||
147 | static inline int video_is_registered(struct video_device *vdev) | ||
145 | { | 148 | { |
146 | return test_bit(V4L2_FL_UNREGISTERED, &vdev->flags); | 149 | return test_bit(V4L2_FL_REGISTERED, &vdev->flags); |
147 | } | 150 | } |
148 | 151 | ||
149 | #endif /* _V4L2_DEV_H */ | 152 | #endif /* _V4L2_DEV_H */ |
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 7a4529defa88..e8ba0f2efbae 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h | |||
@@ -239,6 +239,21 @@ struct v4l2_ioctl_ops { | |||
239 | int (*vidioc_enum_frameintervals) (struct file *file, void *fh, | 239 | int (*vidioc_enum_frameintervals) (struct file *file, void *fh, |
240 | struct v4l2_frmivalenum *fival); | 240 | struct v4l2_frmivalenum *fival); |
241 | 241 | ||
242 | /* DV Timings IOCTLs */ | ||
243 | int (*vidioc_enum_dv_presets) (struct file *file, void *fh, | ||
244 | struct v4l2_dv_enum_preset *preset); | ||
245 | |||
246 | int (*vidioc_s_dv_preset) (struct file *file, void *fh, | ||
247 | struct v4l2_dv_preset *preset); | ||
248 | int (*vidioc_g_dv_preset) (struct file *file, void *fh, | ||
249 | struct v4l2_dv_preset *preset); | ||
250 | int (*vidioc_query_dv_preset) (struct file *file, void *fh, | ||
251 | struct v4l2_dv_preset *qpreset); | ||
252 | int (*vidioc_s_dv_timings) (struct file *file, void *fh, | ||
253 | struct v4l2_dv_timings *timings); | ||
254 | int (*vidioc_g_dv_timings) (struct file *file, void *fh, | ||
255 | struct v4l2_dv_timings *timings); | ||
256 | |||
242 | /* For other private ioctls */ | 257 | /* For other private ioctls */ |
243 | long (*vidioc_default) (struct file *file, void *fh, | 258 | long (*vidioc_default) (struct file *file, void *fh, |
244 | int cmd, void *arg); | 259 | int cmd, void *arg); |
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h new file mode 100644 index 000000000000..0dbe02ada259 --- /dev/null +++ b/include/media/v4l2-mediabus.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Media Bus API header | ||
3 | * | ||
4 | * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef V4L2_MEDIABUS_H | ||
12 | #define V4L2_MEDIABUS_H | ||
13 | |||
14 | /* | ||
15 | * These pixel codes uniquely identify data formats on the media bus. Mostly | ||
16 | * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is | ||
17 | * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the | ||
18 | * data format is fixed. Additionally, "2X8" means that one pixel is transferred | ||
19 | * in two 8-bit samples, "BE" or "LE" specify in which order those samples are | ||
20 | * transferred over the bus: "LE" means that the least significant bits are | ||
21 | * transferred first, "BE" means that the most significant bits are transferred | ||
22 | * first, and "PADHI" and "PADLO" define which bits - low or high, in the | ||
23 | * incomplete high byte, are filled with padding bits. | ||
24 | */ | ||
25 | enum v4l2_mbus_pixelcode { | ||
26 | V4L2_MBUS_FMT_FIXED = 1, | ||
27 | V4L2_MBUS_FMT_YUYV8_2X8_LE, | ||
28 | V4L2_MBUS_FMT_YVYU8_2X8_LE, | ||
29 | V4L2_MBUS_FMT_YUYV8_2X8_BE, | ||
30 | V4L2_MBUS_FMT_YVYU8_2X8_BE, | ||
31 | V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
32 | V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, | ||
33 | V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
34 | V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
35 | V4L2_MBUS_FMT_SBGGR8_1X8, | ||
36 | V4L2_MBUS_FMT_SBGGR10_1X10, | ||
37 | V4L2_MBUS_FMT_GREY8_1X8, | ||
38 | V4L2_MBUS_FMT_Y10_1X10, | ||
39 | V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, | ||
40 | V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, | ||
41 | V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, | ||
42 | V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * struct v4l2_mbus_framefmt - frame format on the media bus | ||
47 | * @width: frame width | ||
48 | * @height: frame height | ||
49 | * @code: data format code | ||
50 | * @field: used interlacing type | ||
51 | * @colorspace: colorspace of the data | ||
52 | */ | ||
53 | struct v4l2_mbus_framefmt { | ||
54 | __u32 width; | ||
55 | __u32 height; | ||
56 | enum v4l2_mbus_pixelcode code; | ||
57 | enum v4l2_field field; | ||
58 | enum v4l2_colorspace colorspace; | ||
59 | }; | ||
60 | |||
61 | #endif | ||
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 00bf17608453..9ba99cd39ee7 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define _V4L2_SUBDEV_H | 22 | #define _V4L2_SUBDEV_H |
23 | 23 | ||
24 | #include <media/v4l2-common.h> | 24 | #include <media/v4l2-common.h> |
25 | #include <media/v4l2-mediabus.h> | ||
25 | 26 | ||
26 | /* generic v4l2_device notify callback notification values */ | 27 | /* generic v4l2_device notify callback notification values */ |
27 | #define V4L2_SUBDEV_IR_RX_NOTIFY _IOW('v', 0, u32) | 28 | #define V4L2_SUBDEV_IR_RX_NOTIFY _IOW('v', 0, u32) |
@@ -207,7 +208,7 @@ struct v4l2_subdev_audio_ops { | |||
207 | s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by | 208 | s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by |
208 | video input devices. | 209 | video input devices. |
209 | 210 | ||
210 | s_crystal_freq: sets the frequency of the crystal used to generate the | 211 | s_crystal_freq: sets the frequency of the crystal used to generate the |
211 | clocks in Hz. An extra flags field allows device specific configuration | 212 | clocks in Hz. An extra flags field allows device specific configuration |
212 | regarding clock frequency dividers, etc. If not used, then set flags | 213 | regarding clock frequency dividers, etc. If not used, then set flags |
213 | to 0. If the frequency is not supported, then -EINVAL is returned. | 214 | to 0. If the frequency is not supported, then -EINVAL is returned. |
@@ -217,6 +218,26 @@ struct v4l2_subdev_audio_ops { | |||
217 | 218 | ||
218 | s_routing: see s_routing in audio_ops, except this version is for video | 219 | s_routing: see s_routing in audio_ops, except this version is for video |
219 | devices. | 220 | devices. |
221 | |||
222 | s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to | ||
223 | s_std() | ||
224 | |||
225 | query_dv_preset: query dv preset in the sub device. This is similar to | ||
226 | querystd() | ||
227 | |||
228 | s_dv_timings(): Set custom dv timings in the sub device. This is used | ||
229 | when sub device is capable of setting detailed timing information | ||
230 | in the hardware to generate/detect the video signal. | ||
231 | |||
232 | g_dv_timings(): Get custom dv timings in the sub device. | ||
233 | |||
234 | enum_mbus_fmt: enumerate pixel formats, provided by a video data source | ||
235 | |||
236 | g_mbus_fmt: get the current pixel format, provided by a video data source | ||
237 | |||
238 | try_mbus_fmt: try to set a pixel format on a video data source | ||
239 | |||
240 | s_mbus_fmt: set a pixel format on a video data source | ||
220 | */ | 241 | */ |
221 | struct v4l2_subdev_video_ops { | 242 | struct v4l2_subdev_video_ops { |
222 | int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); | 243 | int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); |
@@ -240,6 +261,33 @@ struct v4l2_subdev_video_ops { | |||
240 | int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); | 261 | int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); |
241 | int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); | 262 | int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); |
242 | int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); | 263 | int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); |
264 | int (*s_dv_preset)(struct v4l2_subdev *sd, | ||
265 | struct v4l2_dv_preset *preset); | ||
266 | int (*query_dv_preset)(struct v4l2_subdev *sd, | ||
267 | struct v4l2_dv_preset *preset); | ||
268 | int (*s_dv_timings)(struct v4l2_subdev *sd, | ||
269 | struct v4l2_dv_timings *timings); | ||
270 | int (*g_dv_timings)(struct v4l2_subdev *sd, | ||
271 | struct v4l2_dv_timings *timings); | ||
272 | int (*enum_mbus_fmt)(struct v4l2_subdev *sd, int index, | ||
273 | enum v4l2_mbus_pixelcode *code); | ||
274 | int (*g_mbus_fmt)(struct v4l2_subdev *sd, | ||
275 | struct v4l2_mbus_framefmt *fmt); | ||
276 | int (*try_mbus_fmt)(struct v4l2_subdev *sd, | ||
277 | struct v4l2_mbus_framefmt *fmt); | ||
278 | int (*s_mbus_fmt)(struct v4l2_subdev *sd, | ||
279 | struct v4l2_mbus_framefmt *fmt); | ||
280 | }; | ||
281 | |||
282 | /** | ||
283 | * struct v4l2_subdev_sensor_ops - v4l2-subdev sensor operations | ||
284 | * @g_skip_top_lines: number of lines at the top of the image to be skipped. | ||
285 | * This is needed for some sensors, which always corrupt | ||
286 | * several top lines of the output image, or which send their | ||
287 | * metadata in them. | ||
288 | */ | ||
289 | struct v4l2_subdev_sensor_ops { | ||
290 | int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines); | ||
243 | }; | 291 | }; |
244 | 292 | ||
245 | /* | 293 | /* |
@@ -326,11 +374,12 @@ struct v4l2_subdev_ir_ops { | |||
326 | }; | 374 | }; |
327 | 375 | ||
328 | struct v4l2_subdev_ops { | 376 | struct v4l2_subdev_ops { |
329 | const struct v4l2_subdev_core_ops *core; | 377 | const struct v4l2_subdev_core_ops *core; |
330 | const struct v4l2_subdev_tuner_ops *tuner; | 378 | const struct v4l2_subdev_tuner_ops *tuner; |
331 | const struct v4l2_subdev_audio_ops *audio; | 379 | const struct v4l2_subdev_audio_ops *audio; |
332 | const struct v4l2_subdev_video_ops *video; | 380 | const struct v4l2_subdev_video_ops *video; |
333 | const struct v4l2_subdev_ir_ops *ir; | 381 | const struct v4l2_subdev_ir_ops *ir; |
382 | const struct v4l2_subdev_sensor_ops *sensor; | ||
334 | }; | 383 | }; |
335 | 384 | ||
336 | #define V4L2_SUBDEV_NAME_SIZE 32 | 385 | #define V4L2_SUBDEV_NAME_SIZE 32 |
diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h index c051a50ed528..89d43b3d4cb9 100644 --- a/include/video/da8xx-fb.h +++ b/include/video/da8xx-fb.h | |||
@@ -38,6 +38,7 @@ struct da8xx_lcdc_platform_data { | |||
38 | const char manu_name[10]; | 38 | const char manu_name[10]; |
39 | void *controller_data; | 39 | void *controller_data; |
40 | const char type[25]; | 40 | const char type[25]; |
41 | void (*panel_power_ctrl)(int); | ||
41 | }; | 42 | }; |
42 | 43 | ||
43 | struct lcd_ctrl_config { | 44 | struct lcd_ctrl_config { |
@@ -125,6 +125,7 @@ void msg_init_ns(struct ipc_namespace *ns) | |||
125 | void msg_exit_ns(struct ipc_namespace *ns) | 125 | void msg_exit_ns(struct ipc_namespace *ns) |
126 | { | 126 | { |
127 | free_ipcs(ns, &msg_ids(ns), freeque); | 127 | free_ipcs(ns, &msg_ids(ns), freeque); |
128 | idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); | ||
128 | } | 129 | } |
129 | #endif | 130 | #endif |
130 | 131 | ||
@@ -129,6 +129,7 @@ void sem_init_ns(struct ipc_namespace *ns) | |||
129 | void sem_exit_ns(struct ipc_namespace *ns) | 129 | void sem_exit_ns(struct ipc_namespace *ns) |
130 | { | 130 | { |
131 | free_ipcs(ns, &sem_ids(ns), freeary); | 131 | free_ipcs(ns, &sem_ids(ns), freeary); |
132 | idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr); | ||
132 | } | 133 | } |
133 | #endif | 134 | #endif |
134 | 135 | ||
@@ -240,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
240 | key_t key = params->key; | 241 | key_t key = params->key; |
241 | int nsems = params->u.nsems; | 242 | int nsems = params->u.nsems; |
242 | int semflg = params->flg; | 243 | int semflg = params->flg; |
244 | int i; | ||
243 | 245 | ||
244 | if (!nsems) | 246 | if (!nsems) |
245 | return -EINVAL; | 247 | return -EINVAL; |
@@ -272,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
272 | ns->used_sems += nsems; | 274 | ns->used_sems += nsems; |
273 | 275 | ||
274 | sma->sem_base = (struct sem *) &sma[1]; | 276 | sma->sem_base = (struct sem *) &sma[1]; |
277 | |||
278 | for (i = 0; i < nsems; i++) | ||
279 | INIT_LIST_HEAD(&sma->sem_base[i].sem_pending); | ||
280 | |||
281 | sma->complex_count = 0; | ||
275 | INIT_LIST_HEAD(&sma->sem_pending); | 282 | INIT_LIST_HEAD(&sma->sem_pending); |
276 | INIT_LIST_HEAD(&sma->list_id); | 283 | INIT_LIST_HEAD(&sma->list_id); |
277 | sma->sem_nsems = nsems; | 284 | sma->sem_nsems = nsems; |
@@ -397,63 +404,109 @@ undo: | |||
397 | return result; | 404 | return result; |
398 | } | 405 | } |
399 | 406 | ||
400 | /* Go through the pending queue for the indicated semaphore | 407 | /* |
401 | * looking for tasks that can be completed. | 408 | * Wake up a process waiting on the sem queue with a given error. |
409 | * The queue is invalid (may not be accessed) after the function returns. | ||
402 | */ | 410 | */ |
403 | static void update_queue (struct sem_array * sma) | 411 | static void wake_up_sem_queue(struct sem_queue *q, int error) |
404 | { | 412 | { |
405 | int error; | 413 | /* |
406 | struct sem_queue * q; | 414 | * Hold preempt off so that we don't get preempted and have the |
415 | * wakee busy-wait until we're scheduled back on. We're holding | ||
416 | * locks here so it may not strictly be needed, however if the | ||
417 | * locks become preemptible then this prevents such a problem. | ||
418 | */ | ||
419 | preempt_disable(); | ||
420 | q->status = IN_WAKEUP; | ||
421 | wake_up_process(q->sleeper); | ||
422 | /* hands-off: q can disappear immediately after writing q->status. */ | ||
423 | smp_wmb(); | ||
424 | q->status = error; | ||
425 | preempt_enable(); | ||
426 | } | ||
427 | |||
428 | static void unlink_queue(struct sem_array *sma, struct sem_queue *q) | ||
429 | { | ||
430 | list_del(&q->list); | ||
431 | if (q->nsops == 1) | ||
432 | list_del(&q->simple_list); | ||
433 | else | ||
434 | sma->complex_count--; | ||
435 | } | ||
436 | |||
437 | |||
438 | /** | ||
439 | * update_queue(sma, semnum): Look for tasks that can be completed. | ||
440 | * @sma: semaphore array. | ||
441 | * @semnum: semaphore that was modified. | ||
442 | * | ||
443 | * update_queue must be called after a semaphore in a semaphore array | ||
444 | * was modified. If multiple semaphore were modified, then @semnum | ||
445 | * must be set to -1. | ||
446 | */ | ||
447 | static void update_queue(struct sem_array *sma, int semnum) | ||
448 | { | ||
449 | struct sem_queue *q; | ||
450 | struct list_head *walk; | ||
451 | struct list_head *pending_list; | ||
452 | int offset; | ||
453 | |||
454 | /* if there are complex operations around, then knowing the semaphore | ||
455 | * that was modified doesn't help us. Assume that multiple semaphores | ||
456 | * were modified. | ||
457 | */ | ||
458 | if (sma->complex_count) | ||
459 | semnum = -1; | ||
460 | |||
461 | if (semnum == -1) { | ||
462 | pending_list = &sma->sem_pending; | ||
463 | offset = offsetof(struct sem_queue, list); | ||
464 | } else { | ||
465 | pending_list = &sma->sem_base[semnum].sem_pending; | ||
466 | offset = offsetof(struct sem_queue, simple_list); | ||
467 | } | ||
468 | |||
469 | again: | ||
470 | walk = pending_list->next; | ||
471 | while (walk != pending_list) { | ||
472 | int error, alter; | ||
473 | |||
474 | q = (struct sem_queue *)((char *)walk - offset); | ||
475 | walk = walk->next; | ||
476 | |||
477 | /* If we are scanning the single sop, per-semaphore list of | ||
478 | * one semaphore and that semaphore is 0, then it is not | ||
479 | * necessary to scan the "alter" entries: simple increments | ||
480 | * that affect only one entry succeed immediately and cannot | ||
481 | * be in the per semaphore pending queue, and decrements | ||
482 | * cannot be successful if the value is already 0. | ||
483 | */ | ||
484 | if (semnum != -1 && sma->sem_base[semnum].semval == 0 && | ||
485 | q->alter) | ||
486 | break; | ||
407 | 487 | ||
408 | q = list_entry(sma->sem_pending.next, struct sem_queue, list); | ||
409 | while (&q->list != &sma->sem_pending) { | ||
410 | error = try_atomic_semop(sma, q->sops, q->nsops, | 488 | error = try_atomic_semop(sma, q->sops, q->nsops, |
411 | q->undo, q->pid); | 489 | q->undo, q->pid); |
412 | 490 | ||
413 | /* Does q->sleeper still need to sleep? */ | 491 | /* Does q->sleeper still need to sleep? */ |
414 | if (error <= 0) { | 492 | if (error > 0) |
415 | struct sem_queue *n; | 493 | continue; |
416 | |||
417 | /* | ||
418 | * Continue scanning. The next operation | ||
419 | * that must be checked depends on the type of the | ||
420 | * completed operation: | ||
421 | * - if the operation modified the array, then | ||
422 | * restart from the head of the queue and | ||
423 | * check for threads that might be waiting | ||
424 | * for semaphore values to become 0. | ||
425 | * - if the operation didn't modify the array, | ||
426 | * then just continue. | ||
427 | * The order of list_del() and reading ->next | ||
428 | * is crucial: In the former case, the list_del() | ||
429 | * must be done first [because we might be the | ||
430 | * first entry in ->sem_pending], in the latter | ||
431 | * case the list_del() must be done last | ||
432 | * [because the list is invalid after the list_del()] | ||
433 | */ | ||
434 | if (q->alter) { | ||
435 | list_del(&q->list); | ||
436 | n = list_entry(sma->sem_pending.next, | ||
437 | struct sem_queue, list); | ||
438 | } else { | ||
439 | n = list_entry(q->list.next, struct sem_queue, | ||
440 | list); | ||
441 | list_del(&q->list); | ||
442 | } | ||
443 | |||
444 | /* wake up the waiting thread */ | ||
445 | q->status = IN_WAKEUP; | ||
446 | 494 | ||
447 | wake_up_process(q->sleeper); | 495 | unlink_queue(sma, q); |
448 | /* hands-off: q will disappear immediately after | 496 | |
449 | * writing q->status. | 497 | /* |
450 | */ | 498 | * The next operation that must be checked depends on the type |
451 | smp_wmb(); | 499 | * of the completed operation: |
452 | q->status = error; | 500 | * - if the operation modified the array, then restart from the |
453 | q = n; | 501 | * head of the queue and check for threads that might be |
454 | } else { | 502 | * waiting for the new semaphore values. |
455 | q = list_entry(q->list.next, struct sem_queue, list); | 503 | * - if the operation didn't modify the array, then just |
456 | } | 504 | * continue. |
505 | */ | ||
506 | alter = q->alter; | ||
507 | wake_up_sem_queue(q, error); | ||
508 | if (alter && !error) | ||
509 | goto again; | ||
457 | } | 510 | } |
458 | } | 511 | } |
459 | 512 | ||
@@ -533,12 +586,8 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
533 | 586 | ||
534 | /* Wake up all pending processes and let them fail with EIDRM. */ | 587 | /* Wake up all pending processes and let them fail with EIDRM. */ |
535 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { | 588 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { |
536 | list_del(&q->list); | 589 | unlink_queue(sma, q); |
537 | 590 | wake_up_sem_queue(q, -EIDRM); | |
538 | q->status = IN_WAKEUP; | ||
539 | wake_up_process(q->sleeper); /* doesn't sleep */ | ||
540 | smp_wmb(); | ||
541 | q->status = -EIDRM; /* hands-off q */ | ||
542 | } | 591 | } |
543 | 592 | ||
544 | /* Remove the semaphore set from the IDR */ | 593 | /* Remove the semaphore set from the IDR */ |
@@ -575,7 +624,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
575 | static int semctl_nolock(struct ipc_namespace *ns, int semid, | 624 | static int semctl_nolock(struct ipc_namespace *ns, int semid, |
576 | int cmd, int version, union semun arg) | 625 | int cmd, int version, union semun arg) |
577 | { | 626 | { |
578 | int err = -EINVAL; | 627 | int err; |
579 | struct sem_array *sma; | 628 | struct sem_array *sma; |
580 | 629 | ||
581 | switch(cmd) { | 630 | switch(cmd) { |
@@ -652,7 +701,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
652 | default: | 701 | default: |
653 | return -EINVAL; | 702 | return -EINVAL; |
654 | } | 703 | } |
655 | return err; | ||
656 | out_unlock: | 704 | out_unlock: |
657 | sem_unlock(sma); | 705 | sem_unlock(sma); |
658 | return err; | 706 | return err; |
@@ -759,7 +807,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
759 | } | 807 | } |
760 | sma->sem_ctime = get_seconds(); | 808 | sma->sem_ctime = get_seconds(); |
761 | /* maybe some queued-up processes were waiting for this */ | 809 | /* maybe some queued-up processes were waiting for this */ |
762 | update_queue(sma); | 810 | update_queue(sma, -1); |
763 | err = 0; | 811 | err = 0; |
764 | goto out_unlock; | 812 | goto out_unlock; |
765 | } | 813 | } |
@@ -801,7 +849,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
801 | curr->sempid = task_tgid_vnr(current); | 849 | curr->sempid = task_tgid_vnr(current); |
802 | sma->sem_ctime = get_seconds(); | 850 | sma->sem_ctime = get_seconds(); |
803 | /* maybe some queued-up processes were waiting for this */ | 851 | /* maybe some queued-up processes were waiting for this */ |
804 | update_queue(sma); | 852 | update_queue(sma, semnum); |
805 | err = 0; | 853 | err = 0; |
806 | goto out_unlock; | 854 | goto out_unlock; |
807 | } | 855 | } |
@@ -961,17 +1009,31 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) | |||
961 | return 0; | 1009 | return 0; |
962 | } | 1010 | } |
963 | 1011 | ||
964 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | 1012 | static struct sem_undo *__lookup_undo(struct sem_undo_list *ulp, int semid) |
965 | { | 1013 | { |
966 | struct sem_undo *walk; | 1014 | struct sem_undo *un; |
967 | 1015 | ||
968 | list_for_each_entry_rcu(walk, &ulp->list_proc, list_proc) { | 1016 | list_for_each_entry_rcu(un, &ulp->list_proc, list_proc) { |
969 | if (walk->semid == semid) | 1017 | if (un->semid == semid) |
970 | return walk; | 1018 | return un; |
971 | } | 1019 | } |
972 | return NULL; | 1020 | return NULL; |
973 | } | 1021 | } |
974 | 1022 | ||
1023 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | ||
1024 | { | ||
1025 | struct sem_undo *un; | ||
1026 | |||
1027 | assert_spin_locked(&ulp->lock); | ||
1028 | |||
1029 | un = __lookup_undo(ulp, semid); | ||
1030 | if (un) { | ||
1031 | list_del_rcu(&un->list_proc); | ||
1032 | list_add_rcu(&un->list_proc, &ulp->list_proc); | ||
1033 | } | ||
1034 | return un; | ||
1035 | } | ||
1036 | |||
975 | /** | 1037 | /** |
976 | * find_alloc_undo - Lookup (and if not present create) undo array | 1038 | * find_alloc_undo - Lookup (and if not present create) undo array |
977 | * @ns: namespace | 1039 | * @ns: namespace |
@@ -1163,7 +1225,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1163 | error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); | 1225 | error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); |
1164 | if (error <= 0) { | 1226 | if (error <= 0) { |
1165 | if (alter && error == 0) | 1227 | if (alter && error == 0) |
1166 | update_queue (sma); | 1228 | update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1); |
1229 | |||
1167 | goto out_unlock_free; | 1230 | goto out_unlock_free; |
1168 | } | 1231 | } |
1169 | 1232 | ||
@@ -1181,6 +1244,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1181 | else | 1244 | else |
1182 | list_add(&queue.list, &sma->sem_pending); | 1245 | list_add(&queue.list, &sma->sem_pending); |
1183 | 1246 | ||
1247 | if (nsops == 1) { | ||
1248 | struct sem *curr; | ||
1249 | curr = &sma->sem_base[sops->sem_num]; | ||
1250 | |||
1251 | if (alter) | ||
1252 | list_add_tail(&queue.simple_list, &curr->sem_pending); | ||
1253 | else | ||
1254 | list_add(&queue.simple_list, &curr->sem_pending); | ||
1255 | } else { | ||
1256 | INIT_LIST_HEAD(&queue.simple_list); | ||
1257 | sma->complex_count++; | ||
1258 | } | ||
1259 | |||
1184 | queue.status = -EINTR; | 1260 | queue.status = -EINTR; |
1185 | queue.sleeper = current; | 1261 | queue.sleeper = current; |
1186 | current->state = TASK_INTERRUPTIBLE; | 1262 | current->state = TASK_INTERRUPTIBLE; |
@@ -1222,7 +1298,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1222 | */ | 1298 | */ |
1223 | if (timeout && jiffies_left == 0) | 1299 | if (timeout && jiffies_left == 0) |
1224 | error = -EAGAIN; | 1300 | error = -EAGAIN; |
1225 | list_del(&queue.list); | 1301 | unlink_queue(sma, &queue); |
1226 | 1302 | ||
1227 | out_unlock_free: | 1303 | out_unlock_free: |
1228 | sem_unlock(sma); | 1304 | sem_unlock(sma); |
@@ -1307,7 +1383,7 @@ void exit_sem(struct task_struct *tsk) | |||
1307 | if (IS_ERR(sma)) | 1383 | if (IS_ERR(sma)) |
1308 | continue; | 1384 | continue; |
1309 | 1385 | ||
1310 | un = lookup_undo(ulp, semid); | 1386 | un = __lookup_undo(ulp, semid); |
1311 | if (un == NULL) { | 1387 | if (un == NULL) { |
1312 | /* exit_sem raced with IPC_RMID+semget() that created | 1388 | /* exit_sem raced with IPC_RMID+semget() that created |
1313 | * exactly the same semid. Nothing to do. | 1389 | * exactly the same semid. Nothing to do. |
@@ -1351,7 +1427,7 @@ void exit_sem(struct task_struct *tsk) | |||
1351 | } | 1427 | } |
1352 | sma->sem_otime = get_seconds(); | 1428 | sma->sem_otime = get_seconds(); |
1353 | /* maybe some queued-up processes were waiting for this */ | 1429 | /* maybe some queued-up processes were waiting for this */ |
1354 | update_queue(sma); | 1430 | update_queue(sma, -1); |
1355 | sem_unlock(sma); | 1431 | sem_unlock(sma); |
1356 | 1432 | ||
1357 | call_rcu(&un->rcu, free_un); | 1433 | call_rcu(&un->rcu, free_un); |
@@ -1365,7 +1441,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) | |||
1365 | struct sem_array *sma = it; | 1441 | struct sem_array *sma = it; |
1366 | 1442 | ||
1367 | return seq_printf(s, | 1443 | return seq_printf(s, |
1368 | "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", | 1444 | "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n", |
1369 | sma->sem_perm.key, | 1445 | sma->sem_perm.key, |
1370 | sma->sem_perm.id, | 1446 | sma->sem_perm.id, |
1371 | sma->sem_perm.mode, | 1447 | sma->sem_perm.mode, |
@@ -101,6 +101,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
101 | void shm_exit_ns(struct ipc_namespace *ns) | 101 | void shm_exit_ns(struct ipc_namespace *ns) |
102 | { | 102 | { |
103 | free_ipcs(ns, &shm_ids(ns), do_shm_rmid); | 103 | free_ipcs(ns, &shm_ids(ns), do_shm_rmid); |
104 | idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr); | ||
104 | } | 105 | } |
105 | #endif | 106 | #endif |
106 | 107 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 9bd91447e052..202a0ba63d3c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1127,6 +1127,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1127 | #ifdef CONFIG_DEBUG_MUTEXES | 1127 | #ifdef CONFIG_DEBUG_MUTEXES |
1128 | p->blocked_on = NULL; /* not blocked yet */ | 1128 | p->blocked_on = NULL; /* not blocked yet */ |
1129 | #endif | 1129 | #endif |
1130 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | ||
1131 | p->memcg_batch.do_batch = 0; | ||
1132 | p->memcg_batch.memcg = NULL; | ||
1133 | #endif | ||
1130 | 1134 | ||
1131 | p->bts = NULL; | 1135 | p->bts = NULL; |
1132 | 1136 | ||
@@ -1206,9 +1210,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1206 | p->sas_ss_sp = p->sas_ss_size = 0; | 1210 | p->sas_ss_sp = p->sas_ss_size = 0; |
1207 | 1211 | ||
1208 | /* | 1212 | /* |
1209 | * Syscall tracing should be turned off in the child regardless | 1213 | * Syscall tracing and stepping should be turned off in the |
1210 | * of CLONE_PTRACE. | 1214 | * child regardless of CLONE_PTRACE. |
1211 | */ | 1215 | */ |
1216 | user_disable_single_step(p); | ||
1212 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); | 1217 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); |
1213 | #ifdef TIF_SYSCALL_EMU | 1218 | #ifdef TIF_SYSCALL_EMU |
1214 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); | 1219 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); |
diff --git a/kernel/kexec.c b/kernel/kexec.c index f336e2107f98..433e9fcc1fc5 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/cpu.h> | 31 | #include <linux/cpu.h> |
32 | #include <linux/console.h> | 32 | #include <linux/console.h> |
33 | #include <linux/vmalloc.h> | 33 | #include <linux/vmalloc.h> |
34 | #include <linux/swap.h> | ||
34 | 35 | ||
35 | #include <asm/page.h> | 36 | #include <asm/page.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
@@ -1082,6 +1083,64 @@ void crash_kexec(struct pt_regs *regs) | |||
1082 | } | 1083 | } |
1083 | } | 1084 | } |
1084 | 1085 | ||
1086 | size_t crash_get_memory_size(void) | ||
1087 | { | ||
1088 | size_t size; | ||
1089 | mutex_lock(&kexec_mutex); | ||
1090 | size = crashk_res.end - crashk_res.start + 1; | ||
1091 | mutex_unlock(&kexec_mutex); | ||
1092 | return size; | ||
1093 | } | ||
1094 | |||
1095 | static void free_reserved_phys_range(unsigned long begin, unsigned long end) | ||
1096 | { | ||
1097 | unsigned long addr; | ||
1098 | |||
1099 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | ||
1100 | ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); | ||
1101 | init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); | ||
1102 | free_page((unsigned long)__va(addr)); | ||
1103 | totalram_pages++; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | int crash_shrink_memory(unsigned long new_size) | ||
1108 | { | ||
1109 | int ret = 0; | ||
1110 | unsigned long start, end; | ||
1111 | |||
1112 | mutex_lock(&kexec_mutex); | ||
1113 | |||
1114 | if (kexec_crash_image) { | ||
1115 | ret = -ENOENT; | ||
1116 | goto unlock; | ||
1117 | } | ||
1118 | start = crashk_res.start; | ||
1119 | end = crashk_res.end; | ||
1120 | |||
1121 | if (new_size >= end - start + 1) { | ||
1122 | ret = -EINVAL; | ||
1123 | if (new_size == end - start + 1) | ||
1124 | ret = 0; | ||
1125 | goto unlock; | ||
1126 | } | ||
1127 | |||
1128 | start = roundup(start, PAGE_SIZE); | ||
1129 | end = roundup(start + new_size, PAGE_SIZE); | ||
1130 | |||
1131 | free_reserved_phys_range(end, crashk_res.end); | ||
1132 | |||
1133 | if (start == end) { | ||
1134 | crashk_res.end = end; | ||
1135 | release_resource(&crashk_res); | ||
1136 | } else | ||
1137 | crashk_res.end = end - 1; | ||
1138 | |||
1139 | unlock: | ||
1140 | mutex_unlock(&kexec_mutex); | ||
1141 | return ret; | ||
1142 | } | ||
1143 | |||
1085 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | 1144 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, |
1086 | size_t data_len) | 1145 | size_t data_len) |
1087 | { | 1146 | { |
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 528dd78e7e7e..3feaf5a74514 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c | |||
@@ -100,6 +100,26 @@ static ssize_t kexec_crash_loaded_show(struct kobject *kobj, | |||
100 | } | 100 | } |
101 | KERNEL_ATTR_RO(kexec_crash_loaded); | 101 | KERNEL_ATTR_RO(kexec_crash_loaded); |
102 | 102 | ||
103 | static ssize_t kexec_crash_size_show(struct kobject *kobj, | ||
104 | struct kobj_attribute *attr, char *buf) | ||
105 | { | ||
106 | return sprintf(buf, "%zu\n", crash_get_memory_size()); | ||
107 | } | ||
108 | static ssize_t kexec_crash_size_store(struct kobject *kobj, | ||
109 | struct kobj_attribute *attr, | ||
110 | const char *buf, size_t count) | ||
111 | { | ||
112 | unsigned long cnt; | ||
113 | int ret; | ||
114 | |||
115 | if (strict_strtoul(buf, 0, &cnt)) | ||
116 | return -EINVAL; | ||
117 | |||
118 | ret = crash_shrink_memory(cnt); | ||
119 | return ret < 0 ? ret : count; | ||
120 | } | ||
121 | KERNEL_ATTR_RW(kexec_crash_size); | ||
122 | |||
103 | static ssize_t vmcoreinfo_show(struct kobject *kobj, | 123 | static ssize_t vmcoreinfo_show(struct kobject *kobj, |
104 | struct kobj_attribute *attr, char *buf) | 124 | struct kobj_attribute *attr, char *buf) |
105 | { | 125 | { |
@@ -147,6 +167,7 @@ static struct attribute * kernel_attrs[] = { | |||
147 | #ifdef CONFIG_KEXEC | 167 | #ifdef CONFIG_KEXEC |
148 | &kexec_loaded_attr.attr, | 168 | &kexec_loaded_attr.attr, |
149 | &kexec_crash_loaded_attr.attr, | 169 | &kexec_crash_loaded_attr.attr, |
170 | &kexec_crash_size_attr.attr, | ||
150 | &vmcoreinfo_attr.attr, | 171 | &vmcoreinfo_attr.attr, |
151 | #endif | 172 | #endif |
152 | NULL | 173 | NULL |
diff --git a/kernel/pid.c b/kernel/pid.c index d3f722d20f9c..2e17c9c92cbe 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -141,11 +141,12 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) | |||
141 | * installing it: | 141 | * installing it: |
142 | */ | 142 | */ |
143 | spin_lock_irq(&pidmap_lock); | 143 | spin_lock_irq(&pidmap_lock); |
144 | if (map->page) | 144 | if (!map->page) { |
145 | kfree(page); | ||
146 | else | ||
147 | map->page = page; | 145 | map->page = page; |
146 | page = NULL; | ||
147 | } | ||
148 | spin_unlock_irq(&pidmap_lock); | 148 | spin_unlock_irq(&pidmap_lock); |
149 | kfree(page); | ||
149 | if (unlikely(!map->page)) | 150 | if (unlikely(!map->page)) |
150 | break; | 151 | break; |
151 | } | 152 | } |
@@ -268,12 +269,11 @@ struct pid *alloc_pid(struct pid_namespace *ns) | |||
268 | for (type = 0; type < PIDTYPE_MAX; ++type) | 269 | for (type = 0; type < PIDTYPE_MAX; ++type) |
269 | INIT_HLIST_HEAD(&pid->tasks[type]); | 270 | INIT_HLIST_HEAD(&pid->tasks[type]); |
270 | 271 | ||
272 | upid = pid->numbers + ns->level; | ||
271 | spin_lock_irq(&pidmap_lock); | 273 | spin_lock_irq(&pidmap_lock); |
272 | for (i = ns->level; i >= 0; i--) { | 274 | for ( ; upid >= pid->numbers; --upid) |
273 | upid = &pid->numbers[i]; | ||
274 | hlist_add_head_rcu(&upid->pid_chain, | 275 | hlist_add_head_rcu(&upid->pid_chain, |
275 | &pid_hash[pid_hashfn(upid->nr, upid->ns)]); | 276 | &pid_hash[pid_hashfn(upid->nr, upid->ns)]); |
276 | } | ||
277 | spin_unlock_irq(&pidmap_lock); | 277 | spin_unlock_irq(&pidmap_lock); |
278 | 278 | ||
279 | out: | 279 | out: |
diff --git a/kernel/relay.c b/kernel/relay.c index 760c26209a3c..c705a41b4ba3 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
@@ -1198,7 +1198,7 @@ static void relay_pipe_buf_release(struct pipe_inode_info *pipe, | |||
1198 | relay_consume_bytes(rbuf, buf->private); | 1198 | relay_consume_bytes(rbuf, buf->private); |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static struct pipe_buf_operations relay_pipe_buf_ops = { | 1201 | static const struct pipe_buf_operations relay_pipe_buf_ops = { |
1202 | .can_merge = 0, | 1202 | .can_merge = 0, |
1203 | .map = generic_pipe_buf_map, | 1203 | .map = generic_pipe_buf_map, |
1204 | .unmap = generic_pipe_buf_unmap, | 1204 | .unmap = generic_pipe_buf_unmap, |
diff --git a/kernel/signal.c b/kernel/signal.c index 6b982f2cf524..1814e68e4de3 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -423,7 +423,7 @@ still_pending: | |||
423 | */ | 423 | */ |
424 | info->si_signo = sig; | 424 | info->si_signo = sig; |
425 | info->si_errno = 0; | 425 | info->si_errno = 0; |
426 | info->si_code = 0; | 426 | info->si_code = SI_USER; |
427 | info->si_pid = 0; | 427 | info->si_pid = 0; |
428 | info->si_uid = 0; | 428 | info->si_uid = 0; |
429 | } | 429 | } |
@@ -607,6 +607,17 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) | |||
607 | return 1; | 607 | return 1; |
608 | } | 608 | } |
609 | 609 | ||
610 | static inline int is_si_special(const struct siginfo *info) | ||
611 | { | ||
612 | return info <= SEND_SIG_FORCED; | ||
613 | } | ||
614 | |||
615 | static inline bool si_fromuser(const struct siginfo *info) | ||
616 | { | ||
617 | return info == SEND_SIG_NOINFO || | ||
618 | (!is_si_special(info) && SI_FROMUSER(info)); | ||
619 | } | ||
620 | |||
610 | /* | 621 | /* |
611 | * Bad permissions for sending the signal | 622 | * Bad permissions for sending the signal |
612 | * - the caller must hold at least the RCU read lock | 623 | * - the caller must hold at least the RCU read lock |
@@ -621,7 +632,7 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
621 | if (!valid_signal(sig)) | 632 | if (!valid_signal(sig)) |
622 | return -EINVAL; | 633 | return -EINVAL; |
623 | 634 | ||
624 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | 635 | if (!si_fromuser(info)) |
625 | return 0; | 636 | return 0; |
626 | 637 | ||
627 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ | 638 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ |
@@ -949,9 +960,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
949 | int from_ancestor_ns = 0; | 960 | int from_ancestor_ns = 0; |
950 | 961 | ||
951 | #ifdef CONFIG_PID_NS | 962 | #ifdef CONFIG_PID_NS |
952 | if (!is_si_special(info) && SI_FROMUSER(info) && | 963 | from_ancestor_ns = si_fromuser(info) && |
953 | task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0) | 964 | !task_pid_nr_ns(current, task_active_pid_ns(t)); |
954 | from_ancestor_ns = 1; | ||
955 | #endif | 965 | #endif |
956 | 966 | ||
957 | return __send_signal(sig, info, t, group, from_ancestor_ns); | 967 | return __send_signal(sig, info, t, group, from_ancestor_ns); |
@@ -1052,12 +1062,6 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) | |||
1052 | return ret; | 1062 | return ret; |
1053 | } | 1063 | } |
1054 | 1064 | ||
1055 | void | ||
1056 | force_sig_specific(int sig, struct task_struct *t) | ||
1057 | { | ||
1058 | force_sig_info(sig, SEND_SIG_FORCED, t); | ||
1059 | } | ||
1060 | |||
1061 | /* | 1065 | /* |
1062 | * Nuke all other threads in the group. | 1066 | * Nuke all other threads in the group. |
1063 | */ | 1067 | */ |
@@ -1186,8 +1190,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1186 | goto out_unlock; | 1190 | goto out_unlock; |
1187 | } | 1191 | } |
1188 | pcred = __task_cred(p); | 1192 | pcred = __task_cred(p); |
1189 | if ((info == SEND_SIG_NOINFO || | 1193 | if (si_fromuser(info) && |
1190 | (!is_si_special(info) && SI_FROMUSER(info))) && | ||
1191 | euid != pcred->suid && euid != pcred->uid && | 1194 | euid != pcred->suid && euid != pcred->uid && |
1192 | uid != pcred->suid && uid != pcred->uid) { | 1195 | uid != pcred->suid && uid != pcred->uid) { |
1193 | ret = -EPERM; | 1196 | ret = -EPERM; |
@@ -1837,11 +1840,6 @@ relock: | |||
1837 | 1840 | ||
1838 | for (;;) { | 1841 | for (;;) { |
1839 | struct k_sigaction *ka; | 1842 | struct k_sigaction *ka; |
1840 | |||
1841 | if (unlikely(signal->group_stop_count > 0) && | ||
1842 | do_signal_stop(0)) | ||
1843 | goto relock; | ||
1844 | |||
1845 | /* | 1843 | /* |
1846 | * Tracing can induce an artifical signal and choose sigaction. | 1844 | * Tracing can induce an artifical signal and choose sigaction. |
1847 | * The return value in @signr determines the default action, | 1845 | * The return value in @signr determines the default action, |
@@ -1853,6 +1851,10 @@ relock: | |||
1853 | if (unlikely(signr != 0)) | 1851 | if (unlikely(signr != 0)) |
1854 | ka = return_ka; | 1852 | ka = return_ka; |
1855 | else { | 1853 | else { |
1854 | if (unlikely(signal->group_stop_count > 0) && | ||
1855 | do_signal_stop(0)) | ||
1856 | goto relock; | ||
1857 | |||
1856 | signr = dequeue_signal(current, ¤t->blocked, | 1858 | signr = dequeue_signal(current, ¤t->blocked, |
1857 | info); | 1859 | info); |
1858 | 1860 | ||
diff --git a/kernel/time/timecompare.c b/kernel/time/timecompare.c index 96ff643a5a59..12f5c55090be 100644 --- a/kernel/time/timecompare.c +++ b/kernel/time/timecompare.c | |||
@@ -89,7 +89,7 @@ int timecompare_offset(struct timecompare *sync, | |||
89 | * source time | 89 | * source time |
90 | */ | 90 | */ |
91 | sample.offset = | 91 | sample.offset = |
92 | ktime_to_ns(ktime_add(end, start)) / 2 - | 92 | (ktime_to_ns(end) + ktime_to_ns(start)) / 2 - |
93 | ts; | 93 | ts; |
94 | 94 | ||
95 | /* simple insertion sort based on duration */ | 95 | /* simple insertion sort based on duration */ |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index bb6b5e7fa2a2..31118ae16f03 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -3133,7 +3133,7 @@ static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, | |||
3133 | __free_page(spd->pages[idx]); | 3133 | __free_page(spd->pages[idx]); |
3134 | } | 3134 | } |
3135 | 3135 | ||
3136 | static struct pipe_buf_operations tracing_pipe_buf_ops = { | 3136 | static const struct pipe_buf_operations tracing_pipe_buf_ops = { |
3137 | .can_merge = 0, | 3137 | .can_merge = 0, |
3138 | .map = generic_pipe_buf_map, | 3138 | .map = generic_pipe_buf_map, |
3139 | .unmap = generic_pipe_buf_unmap, | 3139 | .unmap = generic_pipe_buf_unmap, |
@@ -3617,7 +3617,7 @@ static void buffer_pipe_buf_get(struct pipe_inode_info *pipe, | |||
3617 | } | 3617 | } |
3618 | 3618 | ||
3619 | /* Pipe buffer operations for a buffer. */ | 3619 | /* Pipe buffer operations for a buffer. */ |
3620 | static struct pipe_buf_operations buffer_pipe_buf_ops = { | 3620 | static const struct pipe_buf_operations buffer_pipe_buf_ops = { |
3621 | .can_merge = 0, | 3621 | .can_merge = 0, |
3622 | .map = generic_pipe_buf_map, | 3622 | .map = generic_pipe_buf_map, |
3623 | .unmap = generic_pipe_buf_unmap, | 3623 | .unmap = generic_pipe_buf_unmap, |
diff --git a/lib/bitmap.c b/lib/bitmap.c index 702565821c99..11bf49750583 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
@@ -271,6 +271,87 @@ int __bitmap_weight(const unsigned long *bitmap, int bits) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL(__bitmap_weight); | 272 | EXPORT_SYMBOL(__bitmap_weight); |
273 | 273 | ||
274 | #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG)) | ||
275 | |||
276 | void bitmap_set(unsigned long *map, int start, int nr) | ||
277 | { | ||
278 | unsigned long *p = map + BIT_WORD(start); | ||
279 | const int size = start + nr; | ||
280 | int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); | ||
281 | unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); | ||
282 | |||
283 | while (nr - bits_to_set >= 0) { | ||
284 | *p |= mask_to_set; | ||
285 | nr -= bits_to_set; | ||
286 | bits_to_set = BITS_PER_LONG; | ||
287 | mask_to_set = ~0UL; | ||
288 | p++; | ||
289 | } | ||
290 | if (nr) { | ||
291 | mask_to_set &= BITMAP_LAST_WORD_MASK(size); | ||
292 | *p |= mask_to_set; | ||
293 | } | ||
294 | } | ||
295 | EXPORT_SYMBOL(bitmap_set); | ||
296 | |||
297 | void bitmap_clear(unsigned long *map, int start, int nr) | ||
298 | { | ||
299 | unsigned long *p = map + BIT_WORD(start); | ||
300 | const int size = start + nr; | ||
301 | int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); | ||
302 | unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); | ||
303 | |||
304 | while (nr - bits_to_clear >= 0) { | ||
305 | *p &= ~mask_to_clear; | ||
306 | nr -= bits_to_clear; | ||
307 | bits_to_clear = BITS_PER_LONG; | ||
308 | mask_to_clear = ~0UL; | ||
309 | p++; | ||
310 | } | ||
311 | if (nr) { | ||
312 | mask_to_clear &= BITMAP_LAST_WORD_MASK(size); | ||
313 | *p &= ~mask_to_clear; | ||
314 | } | ||
315 | } | ||
316 | EXPORT_SYMBOL(bitmap_clear); | ||
317 | |||
318 | /* | ||
319 | * bitmap_find_next_zero_area - find a contiguous aligned zero area | ||
320 | * @map: The address to base the search on | ||
321 | * @size: The bitmap size in bits | ||
322 | * @start: The bitnumber to start searching at | ||
323 | * @nr: The number of zeroed bits we're looking for | ||
324 | * @align_mask: Alignment mask for zero area | ||
325 | * | ||
326 | * The @align_mask should be one less than a power of 2; the effect is that | ||
327 | * the bit offset of all zero areas this function finds is multiples of that | ||
328 | * power of 2. A @align_mask of 0 means no alignment is required. | ||
329 | */ | ||
330 | unsigned long bitmap_find_next_zero_area(unsigned long *map, | ||
331 | unsigned long size, | ||
332 | unsigned long start, | ||
333 | unsigned int nr, | ||
334 | unsigned long align_mask) | ||
335 | { | ||
336 | unsigned long index, end, i; | ||
337 | again: | ||
338 | index = find_next_zero_bit(map, size, start); | ||
339 | |||
340 | /* Align allocation */ | ||
341 | index = __ALIGN_MASK(index, align_mask); | ||
342 | |||
343 | end = index + nr; | ||
344 | if (end > size) | ||
345 | return end; | ||
346 | i = find_next_bit(map, end, index); | ||
347 | if (i < end) { | ||
348 | start = i + 1; | ||
349 | goto again; | ||
350 | } | ||
351 | return index; | ||
352 | } | ||
353 | EXPORT_SYMBOL(bitmap_find_next_zero_area); | ||
354 | |||
274 | /* | 355 | /* |
275 | * Bitmap printing & parsing functions: first version by Bill Irwin, | 356 | * Bitmap printing & parsing functions: first version by Bill Irwin, |
276 | * second version by Paul Jackson, third by Joe Korty. | 357 | * second version by Paul Jackson, third by Joe Korty. |
diff --git a/lib/genalloc.c b/lib/genalloc.c index eed2bdb865e7..e67f97495dd5 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/bitmap.h> | ||
14 | #include <linux/genalloc.h> | 15 | #include <linux/genalloc.h> |
15 | 16 | ||
16 | 17 | ||
@@ -114,7 +115,7 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) | |||
114 | struct gen_pool_chunk *chunk; | 115 | struct gen_pool_chunk *chunk; |
115 | unsigned long addr, flags; | 116 | unsigned long addr, flags; |
116 | int order = pool->min_alloc_order; | 117 | int order = pool->min_alloc_order; |
117 | int nbits, bit, start_bit, end_bit; | 118 | int nbits, start_bit, end_bit; |
118 | 119 | ||
119 | if (size == 0) | 120 | if (size == 0) |
120 | return 0; | 121 | return 0; |
@@ -129,29 +130,19 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) | |||
129 | end_bit -= nbits + 1; | 130 | end_bit -= nbits + 1; |
130 | 131 | ||
131 | spin_lock_irqsave(&chunk->lock, flags); | 132 | spin_lock_irqsave(&chunk->lock, flags); |
132 | bit = -1; | 133 | start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, 0, |
133 | while (bit + 1 < end_bit) { | 134 | nbits, 0); |
134 | bit = find_next_zero_bit(chunk->bits, end_bit, bit + 1); | 135 | if (start_bit >= end_bit) { |
135 | if (bit >= end_bit) | ||
136 | break; | ||
137 | |||
138 | start_bit = bit; | ||
139 | if (nbits > 1) { | ||
140 | bit = find_next_bit(chunk->bits, bit + nbits, | ||
141 | bit + 1); | ||
142 | if (bit - start_bit < nbits) | ||
143 | continue; | ||
144 | } | ||
145 | |||
146 | addr = chunk->start_addr + | ||
147 | ((unsigned long)start_bit << order); | ||
148 | while (nbits--) | ||
149 | __set_bit(start_bit++, chunk->bits); | ||
150 | spin_unlock_irqrestore(&chunk->lock, flags); | 136 | spin_unlock_irqrestore(&chunk->lock, flags); |
151 | read_unlock(&pool->lock); | 137 | continue; |
152 | return addr; | ||
153 | } | 138 | } |
139 | |||
140 | addr = chunk->start_addr + ((unsigned long)start_bit << order); | ||
141 | |||
142 | bitmap_set(chunk->bits, start_bit, nbits); | ||
154 | spin_unlock_irqrestore(&chunk->lock, flags); | 143 | spin_unlock_irqrestore(&chunk->lock, flags); |
144 | read_unlock(&pool->lock); | ||
145 | return addr; | ||
155 | } | 146 | } |
156 | read_unlock(&pool->lock); | 147 | read_unlock(&pool->lock); |
157 | return 0; | 148 | return 0; |
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c index 75dbda03f4fb..c0251f4ad08b 100644 --- a/lib/iommu-helper.c +++ b/lib/iommu-helper.c | |||
@@ -3,41 +3,7 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/bitops.h> | 6 | #include <linux/bitmap.h> |
7 | |||
8 | static unsigned long find_next_zero_area(unsigned long *map, | ||
9 | unsigned long size, | ||
10 | unsigned long start, | ||
11 | unsigned int nr, | ||
12 | unsigned long align_mask) | ||
13 | { | ||
14 | unsigned long index, end, i; | ||
15 | again: | ||
16 | index = find_next_zero_bit(map, size, start); | ||
17 | |||
18 | /* Align allocation */ | ||
19 | index = (index + align_mask) & ~align_mask; | ||
20 | |||
21 | end = index + nr; | ||
22 | if (end >= size) | ||
23 | return -1; | ||
24 | for (i = index; i < end; i++) { | ||
25 | if (test_bit(i, map)) { | ||
26 | start = i+1; | ||
27 | goto again; | ||
28 | } | ||
29 | } | ||
30 | return index; | ||
31 | } | ||
32 | |||
33 | void iommu_area_reserve(unsigned long *map, unsigned long i, int len) | ||
34 | { | ||
35 | unsigned long end = i + len; | ||
36 | while (i < end) { | ||
37 | __set_bit(i, map); | ||
38 | i++; | ||
39 | } | ||
40 | } | ||
41 | 7 | ||
42 | int iommu_is_span_boundary(unsigned int index, unsigned int nr, | 8 | int iommu_is_span_boundary(unsigned int index, unsigned int nr, |
43 | unsigned long shift, | 9 | unsigned long shift, |
@@ -55,31 +21,24 @@ unsigned long iommu_area_alloc(unsigned long *map, unsigned long size, | |||
55 | unsigned long align_mask) | 21 | unsigned long align_mask) |
56 | { | 22 | { |
57 | unsigned long index; | 23 | unsigned long index; |
24 | |||
25 | /* We don't want the last of the limit */ | ||
26 | size -= 1; | ||
58 | again: | 27 | again: |
59 | index = find_next_zero_area(map, size, start, nr, align_mask); | 28 | index = bitmap_find_next_zero_area(map, size, start, nr, align_mask); |
60 | if (index != -1) { | 29 | if (index < size) { |
61 | if (iommu_is_span_boundary(index, nr, shift, boundary_size)) { | 30 | if (iommu_is_span_boundary(index, nr, shift, boundary_size)) { |
62 | /* we could do more effectively */ | 31 | /* we could do more effectively */ |
63 | start = index + 1; | 32 | start = index + 1; |
64 | goto again; | 33 | goto again; |
65 | } | 34 | } |
66 | iommu_area_reserve(map, index, nr); | 35 | bitmap_set(map, index, nr); |
36 | return index; | ||
67 | } | 37 | } |
68 | return index; | 38 | return -1; |
69 | } | 39 | } |
70 | EXPORT_SYMBOL(iommu_area_alloc); | 40 | EXPORT_SYMBOL(iommu_area_alloc); |
71 | 41 | ||
72 | void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr) | ||
73 | { | ||
74 | unsigned long end = start + nr; | ||
75 | |||
76 | while (start < end) { | ||
77 | __clear_bit(start, map); | ||
78 | start++; | ||
79 | } | ||
80 | } | ||
81 | EXPORT_SYMBOL(iommu_area_free); | ||
82 | |||
83 | unsigned long iommu_num_pages(unsigned long addr, unsigned long len, | 42 | unsigned long iommu_num_pages(unsigned long addr, unsigned long len, |
84 | unsigned long io_page_size) | 43 | unsigned long io_page_size) |
85 | { | 44 | { |
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 5bc01803f8f8..437eedb5a53b 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -549,7 +549,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
549 | dma_mask = hwdev->coherent_dma_mask; | 549 | dma_mask = hwdev->coherent_dma_mask; |
550 | 550 | ||
551 | ret = (void *)__get_free_pages(flags, order); | 551 | ret = (void *)__get_free_pages(flags, order); |
552 | if (ret && swiotlb_virt_to_bus(hwdev, ret) + size > dma_mask) { | 552 | if (ret && swiotlb_virt_to_bus(hwdev, ret) + size - 1 > dma_mask) { |
553 | /* | 553 | /* |
554 | * The allocated memory isn't reachable by the device. | 554 | * The allocated memory isn't reachable by the device. |
555 | */ | 555 | */ |
@@ -571,7 +571,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
571 | dev_addr = swiotlb_virt_to_bus(hwdev, ret); | 571 | dev_addr = swiotlb_virt_to_bus(hwdev, ret); |
572 | 572 | ||
573 | /* Confirm address can be DMA'd by device */ | 573 | /* Confirm address can be DMA'd by device */ |
574 | if (dev_addr + size > dma_mask) { | 574 | if (dev_addr + size - 1 > dma_mask) { |
575 | printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", | 575 | printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", |
576 | (unsigned long long)dma_mask, | 576 | (unsigned long long)dma_mask, |
577 | (unsigned long long)dev_addr); | 577 | (unsigned long long)dev_addr); |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e0c2066495e3..878808c4fcbe 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
39 | #include <linux/mm_inline.h> | 39 | #include <linux/mm_inline.h> |
40 | #include <linux/page_cgroup.h> | 40 | #include <linux/page_cgroup.h> |
41 | #include <linux/cpu.h> | ||
41 | #include "internal.h" | 42 | #include "internal.h" |
42 | 43 | ||
43 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
@@ -54,7 +55,6 @@ static int really_do_swap_account __initdata = 1; /* for remember boot option*/ | |||
54 | #define do_swap_account (0) | 55 | #define do_swap_account (0) |
55 | #endif | 56 | #endif |
56 | 57 | ||
57 | static DEFINE_MUTEX(memcg_tasklist); /* can be hold under cgroup_mutex */ | ||
58 | #define SOFTLIMIT_EVENTS_THRESH (1000) | 58 | #define SOFTLIMIT_EVENTS_THRESH (1000) |
59 | 59 | ||
60 | /* | 60 | /* |
@@ -66,7 +66,7 @@ enum mem_cgroup_stat_index { | |||
66 | */ | 66 | */ |
67 | MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ | 67 | MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ |
68 | MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ | 68 | MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ |
69 | MEM_CGROUP_STAT_MAPPED_FILE, /* # of pages charged as file rss */ | 69 | MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ |
70 | MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ | 70 | MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ |
71 | MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ | 71 | MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ |
72 | MEM_CGROUP_STAT_EVENTS, /* sum of pagein + pageout for internal use */ | 72 | MEM_CGROUP_STAT_EVENTS, /* sum of pagein + pageout for internal use */ |
@@ -275,6 +275,7 @@ enum charge_type { | |||
275 | static void mem_cgroup_get(struct mem_cgroup *mem); | 275 | static void mem_cgroup_get(struct mem_cgroup *mem); |
276 | static void mem_cgroup_put(struct mem_cgroup *mem); | 276 | static void mem_cgroup_put(struct mem_cgroup *mem); |
277 | static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem); | 277 | static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *mem); |
278 | static void drain_all_stock_async(void); | ||
278 | 279 | ||
279 | static struct mem_cgroup_per_zone * | 280 | static struct mem_cgroup_per_zone * |
280 | mem_cgroup_zoneinfo(struct mem_cgroup *mem, int nid, int zid) | 281 | mem_cgroup_zoneinfo(struct mem_cgroup *mem, int nid, int zid) |
@@ -758,7 +759,13 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem) | |||
758 | task_unlock(task); | 759 | task_unlock(task); |
759 | if (!curr) | 760 | if (!curr) |
760 | return 0; | 761 | return 0; |
761 | if (curr->use_hierarchy) | 762 | /* |
763 | * We should check use_hierarchy of "mem" not "curr". Because checking | ||
764 | * use_hierarchy of "curr" here make this function true if hierarchy is | ||
765 | * enabled in "curr" and "curr" is a child of "mem" in *cgroup* | ||
766 | * hierarchy(even if use_hierarchy is disabled in "mem"). | ||
767 | */ | ||
768 | if (mem->use_hierarchy) | ||
762 | ret = css_is_ancestor(&curr->css, &mem->css); | 769 | ret = css_is_ancestor(&curr->css, &mem->css); |
763 | else | 770 | else |
764 | ret = (curr == mem); | 771 | ret = (curr == mem); |
@@ -1007,7 +1014,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) | |||
1007 | static char memcg_name[PATH_MAX]; | 1014 | static char memcg_name[PATH_MAX]; |
1008 | int ret; | 1015 | int ret; |
1009 | 1016 | ||
1010 | if (!memcg) | 1017 | if (!memcg || !p) |
1011 | return; | 1018 | return; |
1012 | 1019 | ||
1013 | 1020 | ||
@@ -1137,6 +1144,8 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem, | |||
1137 | victim = mem_cgroup_select_victim(root_mem); | 1144 | victim = mem_cgroup_select_victim(root_mem); |
1138 | if (victim == root_mem) { | 1145 | if (victim == root_mem) { |
1139 | loop++; | 1146 | loop++; |
1147 | if (loop >= 1) | ||
1148 | drain_all_stock_async(); | ||
1140 | if (loop >= 2) { | 1149 | if (loop >= 2) { |
1141 | /* | 1150 | /* |
1142 | * If we have not been able to reclaim | 1151 | * If we have not been able to reclaim |
@@ -1223,7 +1232,7 @@ static void record_last_oom(struct mem_cgroup *mem) | |||
1223 | * Currently used to update mapped file statistics, but the routine can be | 1232 | * Currently used to update mapped file statistics, but the routine can be |
1224 | * generalized to update other statistics as well. | 1233 | * generalized to update other statistics as well. |
1225 | */ | 1234 | */ |
1226 | void mem_cgroup_update_mapped_file_stat(struct page *page, int val) | 1235 | void mem_cgroup_update_file_mapped(struct page *page, int val) |
1227 | { | 1236 | { |
1228 | struct mem_cgroup *mem; | 1237 | struct mem_cgroup *mem; |
1229 | struct mem_cgroup_stat *stat; | 1238 | struct mem_cgroup_stat *stat; |
@@ -1231,9 +1240,6 @@ void mem_cgroup_update_mapped_file_stat(struct page *page, int val) | |||
1231 | int cpu; | 1240 | int cpu; |
1232 | struct page_cgroup *pc; | 1241 | struct page_cgroup *pc; |
1233 | 1242 | ||
1234 | if (!page_is_file_cache(page)) | ||
1235 | return; | ||
1236 | |||
1237 | pc = lookup_page_cgroup(page); | 1243 | pc = lookup_page_cgroup(page); |
1238 | if (unlikely(!pc)) | 1244 | if (unlikely(!pc)) |
1239 | return; | 1245 | return; |
@@ -1253,12 +1259,139 @@ void mem_cgroup_update_mapped_file_stat(struct page *page, int val) | |||
1253 | stat = &mem->stat; | 1259 | stat = &mem->stat; |
1254 | cpustat = &stat->cpustat[cpu]; | 1260 | cpustat = &stat->cpustat[cpu]; |
1255 | 1261 | ||
1256 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, val); | 1262 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED, val); |
1257 | done: | 1263 | done: |
1258 | unlock_page_cgroup(pc); | 1264 | unlock_page_cgroup(pc); |
1259 | } | 1265 | } |
1260 | 1266 | ||
1261 | /* | 1267 | /* |
1268 | * size of first charge trial. "32" comes from vmscan.c's magic value. | ||
1269 | * TODO: maybe necessary to use big numbers in big irons. | ||
1270 | */ | ||
1271 | #define CHARGE_SIZE (32 * PAGE_SIZE) | ||
1272 | struct memcg_stock_pcp { | ||
1273 | struct mem_cgroup *cached; /* this never be root cgroup */ | ||
1274 | int charge; | ||
1275 | struct work_struct work; | ||
1276 | }; | ||
1277 | static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock); | ||
1278 | static atomic_t memcg_drain_count; | ||
1279 | |||
1280 | /* | ||
1281 | * Try to consume stocked charge on this cpu. If success, PAGE_SIZE is consumed | ||
1282 | * from local stock and true is returned. If the stock is 0 or charges from a | ||
1283 | * cgroup which is not current target, returns false. This stock will be | ||
1284 | * refilled. | ||
1285 | */ | ||
1286 | static bool consume_stock(struct mem_cgroup *mem) | ||
1287 | { | ||
1288 | struct memcg_stock_pcp *stock; | ||
1289 | bool ret = true; | ||
1290 | |||
1291 | stock = &get_cpu_var(memcg_stock); | ||
1292 | if (mem == stock->cached && stock->charge) | ||
1293 | stock->charge -= PAGE_SIZE; | ||
1294 | else /* need to call res_counter_charge */ | ||
1295 | ret = false; | ||
1296 | put_cpu_var(memcg_stock); | ||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | /* | ||
1301 | * Returns stocks cached in percpu to res_counter and reset cached information. | ||
1302 | */ | ||
1303 | static void drain_stock(struct memcg_stock_pcp *stock) | ||
1304 | { | ||
1305 | struct mem_cgroup *old = stock->cached; | ||
1306 | |||
1307 | if (stock->charge) { | ||
1308 | res_counter_uncharge(&old->res, stock->charge); | ||
1309 | if (do_swap_account) | ||
1310 | res_counter_uncharge(&old->memsw, stock->charge); | ||
1311 | } | ||
1312 | stock->cached = NULL; | ||
1313 | stock->charge = 0; | ||
1314 | } | ||
1315 | |||
1316 | /* | ||
1317 | * This must be called under preempt disabled or must be called by | ||
1318 | * a thread which is pinned to local cpu. | ||
1319 | */ | ||
1320 | static void drain_local_stock(struct work_struct *dummy) | ||
1321 | { | ||
1322 | struct memcg_stock_pcp *stock = &__get_cpu_var(memcg_stock); | ||
1323 | drain_stock(stock); | ||
1324 | } | ||
1325 | |||
1326 | /* | ||
1327 | * Cache charges(val) which is from res_counter, to local per_cpu area. | ||
1328 | * This will be consumed by consumt_stock() function, later. | ||
1329 | */ | ||
1330 | static void refill_stock(struct mem_cgroup *mem, int val) | ||
1331 | { | ||
1332 | struct memcg_stock_pcp *stock = &get_cpu_var(memcg_stock); | ||
1333 | |||
1334 | if (stock->cached != mem) { /* reset if necessary */ | ||
1335 | drain_stock(stock); | ||
1336 | stock->cached = mem; | ||
1337 | } | ||
1338 | stock->charge += val; | ||
1339 | put_cpu_var(memcg_stock); | ||
1340 | } | ||
1341 | |||
1342 | /* | ||
1343 | * Tries to drain stocked charges in other cpus. This function is asynchronous | ||
1344 | * and just put a work per cpu for draining localy on each cpu. Caller can | ||
1345 | * expects some charges will be back to res_counter later but cannot wait for | ||
1346 | * it. | ||
1347 | */ | ||
1348 | static void drain_all_stock_async(void) | ||
1349 | { | ||
1350 | int cpu; | ||
1351 | /* This function is for scheduling "drain" in asynchronous way. | ||
1352 | * The result of "drain" is not directly handled by callers. Then, | ||
1353 | * if someone is calling drain, we don't have to call drain more. | ||
1354 | * Anyway, WORK_STRUCT_PENDING check in queue_work_on() will catch if | ||
1355 | * there is a race. We just do loose check here. | ||
1356 | */ | ||
1357 | if (atomic_read(&memcg_drain_count)) | ||
1358 | return; | ||
1359 | /* Notify other cpus that system-wide "drain" is running */ | ||
1360 | atomic_inc(&memcg_drain_count); | ||
1361 | get_online_cpus(); | ||
1362 | for_each_online_cpu(cpu) { | ||
1363 | struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); | ||
1364 | schedule_work_on(cpu, &stock->work); | ||
1365 | } | ||
1366 | put_online_cpus(); | ||
1367 | atomic_dec(&memcg_drain_count); | ||
1368 | /* We don't wait for flush_work */ | ||
1369 | } | ||
1370 | |||
1371 | /* This is a synchronous drain interface. */ | ||
1372 | static void drain_all_stock_sync(void) | ||
1373 | { | ||
1374 | /* called when force_empty is called */ | ||
1375 | atomic_inc(&memcg_drain_count); | ||
1376 | schedule_on_each_cpu(drain_local_stock); | ||
1377 | atomic_dec(&memcg_drain_count); | ||
1378 | } | ||
1379 | |||
1380 | static int __cpuinit memcg_stock_cpu_callback(struct notifier_block *nb, | ||
1381 | unsigned long action, | ||
1382 | void *hcpu) | ||
1383 | { | ||
1384 | int cpu = (unsigned long)hcpu; | ||
1385 | struct memcg_stock_pcp *stock; | ||
1386 | |||
1387 | if (action != CPU_DEAD) | ||
1388 | return NOTIFY_OK; | ||
1389 | stock = &per_cpu(memcg_stock, cpu); | ||
1390 | drain_stock(stock); | ||
1391 | return NOTIFY_OK; | ||
1392 | } | ||
1393 | |||
1394 | /* | ||
1262 | * Unlike exported interface, "oom" parameter is added. if oom==true, | 1395 | * Unlike exported interface, "oom" parameter is added. if oom==true, |
1263 | * oom-killer can be invoked. | 1396 | * oom-killer can be invoked. |
1264 | */ | 1397 | */ |
@@ -1269,6 +1402,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
1269 | struct mem_cgroup *mem, *mem_over_limit; | 1402 | struct mem_cgroup *mem, *mem_over_limit; |
1270 | int nr_retries = MEM_CGROUP_RECLAIM_RETRIES; | 1403 | int nr_retries = MEM_CGROUP_RECLAIM_RETRIES; |
1271 | struct res_counter *fail_res; | 1404 | struct res_counter *fail_res; |
1405 | int csize = CHARGE_SIZE; | ||
1272 | 1406 | ||
1273 | if (unlikely(test_thread_flag(TIF_MEMDIE))) { | 1407 | if (unlikely(test_thread_flag(TIF_MEMDIE))) { |
1274 | /* Don't account this! */ | 1408 | /* Don't account this! */ |
@@ -1293,23 +1427,25 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
1293 | return 0; | 1427 | return 0; |
1294 | 1428 | ||
1295 | VM_BUG_ON(css_is_removed(&mem->css)); | 1429 | VM_BUG_ON(css_is_removed(&mem->css)); |
1430 | if (mem_cgroup_is_root(mem)) | ||
1431 | goto done; | ||
1296 | 1432 | ||
1297 | while (1) { | 1433 | while (1) { |
1298 | int ret = 0; | 1434 | int ret = 0; |
1299 | unsigned long flags = 0; | 1435 | unsigned long flags = 0; |
1300 | 1436 | ||
1301 | if (mem_cgroup_is_root(mem)) | 1437 | if (consume_stock(mem)) |
1302 | goto done; | 1438 | goto charged; |
1303 | ret = res_counter_charge(&mem->res, PAGE_SIZE, &fail_res); | 1439 | |
1440 | ret = res_counter_charge(&mem->res, csize, &fail_res); | ||
1304 | if (likely(!ret)) { | 1441 | if (likely(!ret)) { |
1305 | if (!do_swap_account) | 1442 | if (!do_swap_account) |
1306 | break; | 1443 | break; |
1307 | ret = res_counter_charge(&mem->memsw, PAGE_SIZE, | 1444 | ret = res_counter_charge(&mem->memsw, csize, &fail_res); |
1308 | &fail_res); | ||
1309 | if (likely(!ret)) | 1445 | if (likely(!ret)) |
1310 | break; | 1446 | break; |
1311 | /* mem+swap counter fails */ | 1447 | /* mem+swap counter fails */ |
1312 | res_counter_uncharge(&mem->res, PAGE_SIZE); | 1448 | res_counter_uncharge(&mem->res, csize); |
1313 | flags |= MEM_CGROUP_RECLAIM_NOSWAP; | 1449 | flags |= MEM_CGROUP_RECLAIM_NOSWAP; |
1314 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, | 1450 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, |
1315 | memsw); | 1451 | memsw); |
@@ -1318,6 +1454,11 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
1318 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, | 1454 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, |
1319 | res); | 1455 | res); |
1320 | 1456 | ||
1457 | /* reduce request size and retry */ | ||
1458 | if (csize > PAGE_SIZE) { | ||
1459 | csize = PAGE_SIZE; | ||
1460 | continue; | ||
1461 | } | ||
1321 | if (!(gfp_mask & __GFP_WAIT)) | 1462 | if (!(gfp_mask & __GFP_WAIT)) |
1322 | goto nomem; | 1463 | goto nomem; |
1323 | 1464 | ||
@@ -1339,14 +1480,15 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
1339 | 1480 | ||
1340 | if (!nr_retries--) { | 1481 | if (!nr_retries--) { |
1341 | if (oom) { | 1482 | if (oom) { |
1342 | mutex_lock(&memcg_tasklist); | ||
1343 | mem_cgroup_out_of_memory(mem_over_limit, gfp_mask); | 1483 | mem_cgroup_out_of_memory(mem_over_limit, gfp_mask); |
1344 | mutex_unlock(&memcg_tasklist); | ||
1345 | record_last_oom(mem_over_limit); | 1484 | record_last_oom(mem_over_limit); |
1346 | } | 1485 | } |
1347 | goto nomem; | 1486 | goto nomem; |
1348 | } | 1487 | } |
1349 | } | 1488 | } |
1489 | if (csize > PAGE_SIZE) | ||
1490 | refill_stock(mem, csize - PAGE_SIZE); | ||
1491 | charged: | ||
1350 | /* | 1492 | /* |
1351 | * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree. | 1493 | * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree. |
1352 | * if they exceeds softlimit. | 1494 | * if they exceeds softlimit. |
@@ -1361,6 +1503,21 @@ nomem: | |||
1361 | } | 1503 | } |
1362 | 1504 | ||
1363 | /* | 1505 | /* |
1506 | * Somemtimes we have to undo a charge we got by try_charge(). | ||
1507 | * This function is for that and do uncharge, put css's refcnt. | ||
1508 | * gotten by try_charge(). | ||
1509 | */ | ||
1510 | static void mem_cgroup_cancel_charge(struct mem_cgroup *mem) | ||
1511 | { | ||
1512 | if (!mem_cgroup_is_root(mem)) { | ||
1513 | res_counter_uncharge(&mem->res, PAGE_SIZE); | ||
1514 | if (do_swap_account) | ||
1515 | res_counter_uncharge(&mem->memsw, PAGE_SIZE); | ||
1516 | } | ||
1517 | css_put(&mem->css); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1364 | * A helper function to get mem_cgroup from ID. must be called under | 1521 | * A helper function to get mem_cgroup from ID. must be called under |
1365 | * rcu_read_lock(). The caller must check css_is_removed() or some if | 1522 | * rcu_read_lock(). The caller must check css_is_removed() or some if |
1366 | * it's concern. (dropping refcnt from swap can be called against removed | 1523 | * it's concern. (dropping refcnt from swap can be called against removed |
@@ -1426,12 +1583,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, | |||
1426 | lock_page_cgroup(pc); | 1583 | lock_page_cgroup(pc); |
1427 | if (unlikely(PageCgroupUsed(pc))) { | 1584 | if (unlikely(PageCgroupUsed(pc))) { |
1428 | unlock_page_cgroup(pc); | 1585 | unlock_page_cgroup(pc); |
1429 | if (!mem_cgroup_is_root(mem)) { | 1586 | mem_cgroup_cancel_charge(mem); |
1430 | res_counter_uncharge(&mem->res, PAGE_SIZE); | ||
1431 | if (do_swap_account) | ||
1432 | res_counter_uncharge(&mem->memsw, PAGE_SIZE); | ||
1433 | } | ||
1434 | css_put(&mem->css); | ||
1435 | return; | 1587 | return; |
1436 | } | 1588 | } |
1437 | 1589 | ||
@@ -1464,27 +1616,22 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, | |||
1464 | } | 1616 | } |
1465 | 1617 | ||
1466 | /** | 1618 | /** |
1467 | * mem_cgroup_move_account - move account of the page | 1619 | * __mem_cgroup_move_account - move account of the page |
1468 | * @pc: page_cgroup of the page. | 1620 | * @pc: page_cgroup of the page. |
1469 | * @from: mem_cgroup which the page is moved from. | 1621 | * @from: mem_cgroup which the page is moved from. |
1470 | * @to: mem_cgroup which the page is moved to. @from != @to. | 1622 | * @to: mem_cgroup which the page is moved to. @from != @to. |
1471 | * | 1623 | * |
1472 | * The caller must confirm following. | 1624 | * The caller must confirm following. |
1473 | * - page is not on LRU (isolate_page() is useful.) | 1625 | * - page is not on LRU (isolate_page() is useful.) |
1474 | * | 1626 | * - the pc is locked, used, and ->mem_cgroup points to @from. |
1475 | * returns 0 at success, | ||
1476 | * returns -EBUSY when lock is busy or "pc" is unstable. | ||
1477 | * | 1627 | * |
1478 | * This function does "uncharge" from old cgroup but doesn't do "charge" to | 1628 | * This function does "uncharge" from old cgroup but doesn't do "charge" to |
1479 | * new cgroup. It should be done by a caller. | 1629 | * new cgroup. It should be done by a caller. |
1480 | */ | 1630 | */ |
1481 | 1631 | ||
1482 | static int mem_cgroup_move_account(struct page_cgroup *pc, | 1632 | static void __mem_cgroup_move_account(struct page_cgroup *pc, |
1483 | struct mem_cgroup *from, struct mem_cgroup *to) | 1633 | struct mem_cgroup *from, struct mem_cgroup *to) |
1484 | { | 1634 | { |
1485 | struct mem_cgroup_per_zone *from_mz, *to_mz; | ||
1486 | int nid, zid; | ||
1487 | int ret = -EBUSY; | ||
1488 | struct page *page; | 1635 | struct page *page; |
1489 | int cpu; | 1636 | int cpu; |
1490 | struct mem_cgroup_stat *stat; | 1637 | struct mem_cgroup_stat *stat; |
@@ -1492,38 +1639,27 @@ static int mem_cgroup_move_account(struct page_cgroup *pc, | |||
1492 | 1639 | ||
1493 | VM_BUG_ON(from == to); | 1640 | VM_BUG_ON(from == to); |
1494 | VM_BUG_ON(PageLRU(pc->page)); | 1641 | VM_BUG_ON(PageLRU(pc->page)); |
1495 | 1642 | VM_BUG_ON(!PageCgroupLocked(pc)); | |
1496 | nid = page_cgroup_nid(pc); | 1643 | VM_BUG_ON(!PageCgroupUsed(pc)); |
1497 | zid = page_cgroup_zid(pc); | 1644 | VM_BUG_ON(pc->mem_cgroup != from); |
1498 | from_mz = mem_cgroup_zoneinfo(from, nid, zid); | ||
1499 | to_mz = mem_cgroup_zoneinfo(to, nid, zid); | ||
1500 | |||
1501 | if (!trylock_page_cgroup(pc)) | ||
1502 | return ret; | ||
1503 | |||
1504 | if (!PageCgroupUsed(pc)) | ||
1505 | goto out; | ||
1506 | |||
1507 | if (pc->mem_cgroup != from) | ||
1508 | goto out; | ||
1509 | 1645 | ||
1510 | if (!mem_cgroup_is_root(from)) | 1646 | if (!mem_cgroup_is_root(from)) |
1511 | res_counter_uncharge(&from->res, PAGE_SIZE); | 1647 | res_counter_uncharge(&from->res, PAGE_SIZE); |
1512 | mem_cgroup_charge_statistics(from, pc, false); | 1648 | mem_cgroup_charge_statistics(from, pc, false); |
1513 | 1649 | ||
1514 | page = pc->page; | 1650 | page = pc->page; |
1515 | if (page_is_file_cache(page) && page_mapped(page)) { | 1651 | if (page_mapped(page) && !PageAnon(page)) { |
1516 | cpu = smp_processor_id(); | 1652 | cpu = smp_processor_id(); |
1517 | /* Update mapped_file data for mem_cgroup "from" */ | 1653 | /* Update mapped_file data for mem_cgroup "from" */ |
1518 | stat = &from->stat; | 1654 | stat = &from->stat; |
1519 | cpustat = &stat->cpustat[cpu]; | 1655 | cpustat = &stat->cpustat[cpu]; |
1520 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, | 1656 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED, |
1521 | -1); | 1657 | -1); |
1522 | 1658 | ||
1523 | /* Update mapped_file data for mem_cgroup "to" */ | 1659 | /* Update mapped_file data for mem_cgroup "to" */ |
1524 | stat = &to->stat; | 1660 | stat = &to->stat; |
1525 | cpustat = &stat->cpustat[cpu]; | 1661 | cpustat = &stat->cpustat[cpu]; |
1526 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, | 1662 | __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_FILE_MAPPED, |
1527 | 1); | 1663 | 1); |
1528 | } | 1664 | } |
1529 | 1665 | ||
@@ -1534,15 +1670,28 @@ static int mem_cgroup_move_account(struct page_cgroup *pc, | |||
1534 | css_get(&to->css); | 1670 | css_get(&to->css); |
1535 | pc->mem_cgroup = to; | 1671 | pc->mem_cgroup = to; |
1536 | mem_cgroup_charge_statistics(to, pc, true); | 1672 | mem_cgroup_charge_statistics(to, pc, true); |
1537 | ret = 0; | ||
1538 | out: | ||
1539 | unlock_page_cgroup(pc); | ||
1540 | /* | 1673 | /* |
1541 | * We charges against "to" which may not have any tasks. Then, "to" | 1674 | * We charges against "to" which may not have any tasks. Then, "to" |
1542 | * can be under rmdir(). But in current implementation, caller of | 1675 | * can be under rmdir(). But in current implementation, caller of |
1543 | * this function is just force_empty() and it's garanteed that | 1676 | * this function is just force_empty() and it's garanteed that |
1544 | * "to" is never removed. So, we don't check rmdir status here. | 1677 | * "to" is never removed. So, we don't check rmdir status here. |
1545 | */ | 1678 | */ |
1679 | } | ||
1680 | |||
1681 | /* | ||
1682 | * check whether the @pc is valid for moving account and call | ||
1683 | * __mem_cgroup_move_account() | ||
1684 | */ | ||
1685 | static int mem_cgroup_move_account(struct page_cgroup *pc, | ||
1686 | struct mem_cgroup *from, struct mem_cgroup *to) | ||
1687 | { | ||
1688 | int ret = -EINVAL; | ||
1689 | lock_page_cgroup(pc); | ||
1690 | if (PageCgroupUsed(pc) && pc->mem_cgroup == from) { | ||
1691 | __mem_cgroup_move_account(pc, from, to); | ||
1692 | ret = 0; | ||
1693 | } | ||
1694 | unlock_page_cgroup(pc); | ||
1546 | return ret; | 1695 | return ret; |
1547 | } | 1696 | } |
1548 | 1697 | ||
@@ -1564,45 +1713,27 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc, | |||
1564 | if (!pcg) | 1713 | if (!pcg) |
1565 | return -EINVAL; | 1714 | return -EINVAL; |
1566 | 1715 | ||
1716 | ret = -EBUSY; | ||
1717 | if (!get_page_unless_zero(page)) | ||
1718 | goto out; | ||
1719 | if (isolate_lru_page(page)) | ||
1720 | goto put; | ||
1567 | 1721 | ||
1568 | parent = mem_cgroup_from_cont(pcg); | 1722 | parent = mem_cgroup_from_cont(pcg); |
1569 | |||
1570 | |||
1571 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false, page); | 1723 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false, page); |
1572 | if (ret || !parent) | 1724 | if (ret || !parent) |
1573 | return ret; | 1725 | goto put_back; |
1574 | |||
1575 | if (!get_page_unless_zero(page)) { | ||
1576 | ret = -EBUSY; | ||
1577 | goto uncharge; | ||
1578 | } | ||
1579 | |||
1580 | ret = isolate_lru_page(page); | ||
1581 | |||
1582 | if (ret) | ||
1583 | goto cancel; | ||
1584 | 1726 | ||
1585 | ret = mem_cgroup_move_account(pc, child, parent); | 1727 | ret = mem_cgroup_move_account(pc, child, parent); |
1586 | 1728 | if (!ret) | |
1729 | css_put(&parent->css); /* drop extra refcnt by try_charge() */ | ||
1730 | else | ||
1731 | mem_cgroup_cancel_charge(parent); /* does css_put */ | ||
1732 | put_back: | ||
1587 | putback_lru_page(page); | 1733 | putback_lru_page(page); |
1588 | if (!ret) { | 1734 | put: |
1589 | put_page(page); | ||
1590 | /* drop extra refcnt by try_charge() */ | ||
1591 | css_put(&parent->css); | ||
1592 | return 0; | ||
1593 | } | ||
1594 | |||
1595 | cancel: | ||
1596 | put_page(page); | 1735 | put_page(page); |
1597 | uncharge: | 1736 | out: |
1598 | /* drop extra refcnt by try_charge() */ | ||
1599 | css_put(&parent->css); | ||
1600 | /* uncharge if move fails */ | ||
1601 | if (!mem_cgroup_is_root(parent)) { | ||
1602 | res_counter_uncharge(&parent->res, PAGE_SIZE); | ||
1603 | if (do_swap_account) | ||
1604 | res_counter_uncharge(&parent->memsw, PAGE_SIZE); | ||
1605 | } | ||
1606 | return ret; | 1737 | return ret; |
1607 | } | 1738 | } |
1608 | 1739 | ||
@@ -1819,14 +1950,53 @@ void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *mem) | |||
1819 | return; | 1950 | return; |
1820 | if (!mem) | 1951 | if (!mem) |
1821 | return; | 1952 | return; |
1822 | if (!mem_cgroup_is_root(mem)) { | 1953 | mem_cgroup_cancel_charge(mem); |
1823 | res_counter_uncharge(&mem->res, PAGE_SIZE); | ||
1824 | if (do_swap_account) | ||
1825 | res_counter_uncharge(&mem->memsw, PAGE_SIZE); | ||
1826 | } | ||
1827 | css_put(&mem->css); | ||
1828 | } | 1954 | } |
1829 | 1955 | ||
1956 | static void | ||
1957 | __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype) | ||
1958 | { | ||
1959 | struct memcg_batch_info *batch = NULL; | ||
1960 | bool uncharge_memsw = true; | ||
1961 | /* If swapout, usage of swap doesn't decrease */ | ||
1962 | if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT) | ||
1963 | uncharge_memsw = false; | ||
1964 | /* | ||
1965 | * do_batch > 0 when unmapping pages or inode invalidate/truncate. | ||
1966 | * In those cases, all pages freed continously can be expected to be in | ||
1967 | * the same cgroup and we have chance to coalesce uncharges. | ||
1968 | * But we do uncharge one by one if this is killed by OOM(TIF_MEMDIE) | ||
1969 | * because we want to do uncharge as soon as possible. | ||
1970 | */ | ||
1971 | if (!current->memcg_batch.do_batch || test_thread_flag(TIF_MEMDIE)) | ||
1972 | goto direct_uncharge; | ||
1973 | |||
1974 | batch = ¤t->memcg_batch; | ||
1975 | /* | ||
1976 | * In usual, we do css_get() when we remember memcg pointer. | ||
1977 | * But in this case, we keep res->usage until end of a series of | ||
1978 | * uncharges. Then, it's ok to ignore memcg's refcnt. | ||
1979 | */ | ||
1980 | if (!batch->memcg) | ||
1981 | batch->memcg = mem; | ||
1982 | /* | ||
1983 | * In typical case, batch->memcg == mem. This means we can | ||
1984 | * merge a series of uncharges to an uncharge of res_counter. | ||
1985 | * If not, we uncharge res_counter ony by one. | ||
1986 | */ | ||
1987 | if (batch->memcg != mem) | ||
1988 | goto direct_uncharge; | ||
1989 | /* remember freed charge and uncharge it later */ | ||
1990 | batch->bytes += PAGE_SIZE; | ||
1991 | if (uncharge_memsw) | ||
1992 | batch->memsw_bytes += PAGE_SIZE; | ||
1993 | return; | ||
1994 | direct_uncharge: | ||
1995 | res_counter_uncharge(&mem->res, PAGE_SIZE); | ||
1996 | if (uncharge_memsw) | ||
1997 | res_counter_uncharge(&mem->memsw, PAGE_SIZE); | ||
1998 | return; | ||
1999 | } | ||
1830 | 2000 | ||
1831 | /* | 2001 | /* |
1832 | * uncharge if !page_mapped(page) | 2002 | * uncharge if !page_mapped(page) |
@@ -1875,12 +2045,8 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | |||
1875 | break; | 2045 | break; |
1876 | } | 2046 | } |
1877 | 2047 | ||
1878 | if (!mem_cgroup_is_root(mem)) { | 2048 | if (!mem_cgroup_is_root(mem)) |
1879 | res_counter_uncharge(&mem->res, PAGE_SIZE); | 2049 | __do_uncharge(mem, ctype); |
1880 | if (do_swap_account && | ||
1881 | (ctype != MEM_CGROUP_CHARGE_TYPE_SWAPOUT)) | ||
1882 | res_counter_uncharge(&mem->memsw, PAGE_SIZE); | ||
1883 | } | ||
1884 | if (ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT) | 2050 | if (ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT) |
1885 | mem_cgroup_swap_statistics(mem, true); | 2051 | mem_cgroup_swap_statistics(mem, true); |
1886 | mem_cgroup_charge_statistics(mem, pc, false); | 2052 | mem_cgroup_charge_statistics(mem, pc, false); |
@@ -1926,6 +2092,50 @@ void mem_cgroup_uncharge_cache_page(struct page *page) | |||
1926 | __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_CACHE); | 2092 | __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_CACHE); |
1927 | } | 2093 | } |
1928 | 2094 | ||
2095 | /* | ||
2096 | * Batch_start/batch_end is called in unmap_page_range/invlidate/trucate. | ||
2097 | * In that cases, pages are freed continuously and we can expect pages | ||
2098 | * are in the same memcg. All these calls itself limits the number of | ||
2099 | * pages freed at once, then uncharge_start/end() is called properly. | ||
2100 | * This may be called prural(2) times in a context, | ||
2101 | */ | ||
2102 | |||
2103 | void mem_cgroup_uncharge_start(void) | ||
2104 | { | ||
2105 | current->memcg_batch.do_batch++; | ||
2106 | /* We can do nest. */ | ||
2107 | if (current->memcg_batch.do_batch == 1) { | ||
2108 | current->memcg_batch.memcg = NULL; | ||
2109 | current->memcg_batch.bytes = 0; | ||
2110 | current->memcg_batch.memsw_bytes = 0; | ||
2111 | } | ||
2112 | } | ||
2113 | |||
2114 | void mem_cgroup_uncharge_end(void) | ||
2115 | { | ||
2116 | struct memcg_batch_info *batch = ¤t->memcg_batch; | ||
2117 | |||
2118 | if (!batch->do_batch) | ||
2119 | return; | ||
2120 | |||
2121 | batch->do_batch--; | ||
2122 | if (batch->do_batch) /* If stacked, do nothing. */ | ||
2123 | return; | ||
2124 | |||
2125 | if (!batch->memcg) | ||
2126 | return; | ||
2127 | /* | ||
2128 | * This "batch->memcg" is valid without any css_get/put etc... | ||
2129 | * bacause we hide charges behind us. | ||
2130 | */ | ||
2131 | if (batch->bytes) | ||
2132 | res_counter_uncharge(&batch->memcg->res, batch->bytes); | ||
2133 | if (batch->memsw_bytes) | ||
2134 | res_counter_uncharge(&batch->memcg->memsw, batch->memsw_bytes); | ||
2135 | /* forget this pointer (for sanity check) */ | ||
2136 | batch->memcg = NULL; | ||
2137 | } | ||
2138 | |||
1929 | #ifdef CONFIG_SWAP | 2139 | #ifdef CONFIG_SWAP |
1930 | /* | 2140 | /* |
1931 | * called after __delete_from_swap_cache() and drop "page" account. | 2141 | * called after __delete_from_swap_cache() and drop "page" account. |
@@ -2101,7 +2311,6 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, | |||
2101 | unsigned long long val) | 2311 | unsigned long long val) |
2102 | { | 2312 | { |
2103 | int retry_count; | 2313 | int retry_count; |
2104 | int progress; | ||
2105 | u64 memswlimit; | 2314 | u64 memswlimit; |
2106 | int ret = 0; | 2315 | int ret = 0; |
2107 | int children = mem_cgroup_count_children(memcg); | 2316 | int children = mem_cgroup_count_children(memcg); |
@@ -2145,8 +2354,7 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, | |||
2145 | if (!ret) | 2354 | if (!ret) |
2146 | break; | 2355 | break; |
2147 | 2356 | ||
2148 | progress = mem_cgroup_hierarchical_reclaim(memcg, NULL, | 2357 | mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL, |
2149 | GFP_KERNEL, | ||
2150 | MEM_CGROUP_RECLAIM_SHRINK); | 2358 | MEM_CGROUP_RECLAIM_SHRINK); |
2151 | curusage = res_counter_read_u64(&memcg->res, RES_USAGE); | 2359 | curusage = res_counter_read_u64(&memcg->res, RES_USAGE); |
2152 | /* Usage is reduced ? */ | 2360 | /* Usage is reduced ? */ |
@@ -2385,6 +2593,7 @@ move_account: | |||
2385 | goto out; | 2593 | goto out; |
2386 | /* This is for making all *used* pages to be on LRU. */ | 2594 | /* This is for making all *used* pages to be on LRU. */ |
2387 | lru_add_drain_all(); | 2595 | lru_add_drain_all(); |
2596 | drain_all_stock_sync(); | ||
2388 | ret = 0; | 2597 | ret = 0; |
2389 | for_each_node_state(node, N_HIGH_MEMORY) { | 2598 | for_each_node_state(node, N_HIGH_MEMORY) { |
2390 | for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) { | 2599 | for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) { |
@@ -2542,6 +2751,7 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) | |||
2542 | val += idx_val; | 2751 | val += idx_val; |
2543 | mem_cgroup_get_recursive_idx_stat(mem, | 2752 | mem_cgroup_get_recursive_idx_stat(mem, |
2544 | MEM_CGROUP_STAT_SWAPOUT, &idx_val); | 2753 | MEM_CGROUP_STAT_SWAPOUT, &idx_val); |
2754 | val += idx_val; | ||
2545 | val <<= PAGE_SHIFT; | 2755 | val <<= PAGE_SHIFT; |
2546 | } else | 2756 | } else |
2547 | val = res_counter_read_u64(&mem->memsw, name); | 2757 | val = res_counter_read_u64(&mem->memsw, name); |
@@ -2661,7 +2871,7 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) | |||
2661 | enum { | 2871 | enum { |
2662 | MCS_CACHE, | 2872 | MCS_CACHE, |
2663 | MCS_RSS, | 2873 | MCS_RSS, |
2664 | MCS_MAPPED_FILE, | 2874 | MCS_FILE_MAPPED, |
2665 | MCS_PGPGIN, | 2875 | MCS_PGPGIN, |
2666 | MCS_PGPGOUT, | 2876 | MCS_PGPGOUT, |
2667 | MCS_SWAP, | 2877 | MCS_SWAP, |
@@ -2705,8 +2915,8 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data) | |||
2705 | s->stat[MCS_CACHE] += val * PAGE_SIZE; | 2915 | s->stat[MCS_CACHE] += val * PAGE_SIZE; |
2706 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS); | 2916 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS); |
2707 | s->stat[MCS_RSS] += val * PAGE_SIZE; | 2917 | s->stat[MCS_RSS] += val * PAGE_SIZE; |
2708 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_MAPPED_FILE); | 2918 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_FILE_MAPPED); |
2709 | s->stat[MCS_MAPPED_FILE] += val * PAGE_SIZE; | 2919 | s->stat[MCS_FILE_MAPPED] += val * PAGE_SIZE; |
2710 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT); | 2920 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT); |
2711 | s->stat[MCS_PGPGIN] += val; | 2921 | s->stat[MCS_PGPGIN] += val; |
2712 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT); | 2922 | val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT); |
@@ -3098,11 +3308,18 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) | |||
3098 | 3308 | ||
3099 | /* root ? */ | 3309 | /* root ? */ |
3100 | if (cont->parent == NULL) { | 3310 | if (cont->parent == NULL) { |
3311 | int cpu; | ||
3101 | enable_swap_cgroup(); | 3312 | enable_swap_cgroup(); |
3102 | parent = NULL; | 3313 | parent = NULL; |
3103 | root_mem_cgroup = mem; | 3314 | root_mem_cgroup = mem; |
3104 | if (mem_cgroup_soft_limit_tree_init()) | 3315 | if (mem_cgroup_soft_limit_tree_init()) |
3105 | goto free_out; | 3316 | goto free_out; |
3317 | for_each_possible_cpu(cpu) { | ||
3318 | struct memcg_stock_pcp *stock = | ||
3319 | &per_cpu(memcg_stock, cpu); | ||
3320 | INIT_WORK(&stock->work, drain_local_stock); | ||
3321 | } | ||
3322 | hotcpu_notifier(memcg_stock_cpu_callback, 0); | ||
3106 | 3323 | ||
3107 | } else { | 3324 | } else { |
3108 | parent = mem_cgroup_from_cont(cont->parent); | 3325 | parent = mem_cgroup_from_cont(cont->parent); |
@@ -3171,12 +3388,10 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, | |||
3171 | struct task_struct *p, | 3388 | struct task_struct *p, |
3172 | bool threadgroup) | 3389 | bool threadgroup) |
3173 | { | 3390 | { |
3174 | mutex_lock(&memcg_tasklist); | ||
3175 | /* | 3391 | /* |
3176 | * FIXME: It's better to move charges of this process from old | 3392 | * FIXME: It's better to move charges of this process from old |
3177 | * memcg to new memcg. But it's just on TODO-List now. | 3393 | * memcg to new memcg. But it's just on TODO-List now. |
3178 | */ | 3394 | */ |
3179 | mutex_unlock(&memcg_tasklist); | ||
3180 | } | 3395 | } |
3181 | 3396 | ||
3182 | struct cgroup_subsys mem_cgroup_subsys = { | 3397 | struct cgroup_subsys mem_cgroup_subsys = { |
diff --git a/mm/memory.c b/mm/memory.c index a54b2c498444..aed45eaf8ac9 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -956,6 +956,7 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb, | |||
956 | details = NULL; | 956 | details = NULL; |
957 | 957 | ||
958 | BUG_ON(addr >= end); | 958 | BUG_ON(addr >= end); |
959 | mem_cgroup_uncharge_start(); | ||
959 | tlb_start_vma(tlb, vma); | 960 | tlb_start_vma(tlb, vma); |
960 | pgd = pgd_offset(vma->vm_mm, addr); | 961 | pgd = pgd_offset(vma->vm_mm, addr); |
961 | do { | 962 | do { |
@@ -968,6 +969,7 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb, | |||
968 | zap_work, details); | 969 | zap_work, details); |
969 | } while (pgd++, addr = next, (addr != end && *zap_work > 0)); | 970 | } while (pgd++, addr = next, (addr != end && *zap_work > 0)); |
970 | tlb_end_vma(tlb, vma); | 971 | tlb_end_vma(tlb, vma); |
972 | mem_cgroup_uncharge_end(); | ||
971 | 973 | ||
972 | return addr; | 974 | return addr; |
973 | } | 975 | } |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 492c98624fc1..f52481b1c1e5 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -196,27 +196,46 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) | |||
196 | /* | 196 | /* |
197 | * Determine the type of allocation constraint. | 197 | * Determine the type of allocation constraint. |
198 | */ | 198 | */ |
199 | static inline enum oom_constraint constrained_alloc(struct zonelist *zonelist, | ||
200 | gfp_t gfp_mask) | ||
201 | { | ||
202 | #ifdef CONFIG_NUMA | 199 | #ifdef CONFIG_NUMA |
200 | static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | ||
201 | gfp_t gfp_mask, nodemask_t *nodemask) | ||
202 | { | ||
203 | struct zone *zone; | 203 | struct zone *zone; |
204 | struct zoneref *z; | 204 | struct zoneref *z; |
205 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); | 205 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); |
206 | nodemask_t nodes = node_states[N_HIGH_MEMORY]; | ||
207 | 206 | ||
208 | for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) | 207 | /* |
209 | if (cpuset_zone_allowed_softwall(zone, gfp_mask)) | 208 | * Reach here only when __GFP_NOFAIL is used. So, we should avoid |
210 | node_clear(zone_to_nid(zone), nodes); | 209 | * to kill current.We have to random task kill in this case. |
211 | else | 210 | * Hopefully, CONSTRAINT_THISNODE...but no way to handle it, now. |
212 | return CONSTRAINT_CPUSET; | 211 | */ |
212 | if (gfp_mask & __GFP_THISNODE) | ||
213 | return CONSTRAINT_NONE; | ||
213 | 214 | ||
214 | if (!nodes_empty(nodes)) | 215 | /* |
216 | * The nodemask here is a nodemask passed to alloc_pages(). Now, | ||
217 | * cpuset doesn't use this nodemask for its hardwall/softwall/hierarchy | ||
218 | * feature. mempolicy is an only user of nodemask here. | ||
219 | * check mempolicy's nodemask contains all N_HIGH_MEMORY | ||
220 | */ | ||
221 | if (nodemask && !nodes_subset(node_states[N_HIGH_MEMORY], *nodemask)) | ||
215 | return CONSTRAINT_MEMORY_POLICY; | 222 | return CONSTRAINT_MEMORY_POLICY; |
216 | #endif | 223 | |
224 | /* Check this allocation failure is caused by cpuset's wall function */ | ||
225 | for_each_zone_zonelist_nodemask(zone, z, zonelist, | ||
226 | high_zoneidx, nodemask) | ||
227 | if (!cpuset_zone_allowed_softwall(zone, gfp_mask)) | ||
228 | return CONSTRAINT_CPUSET; | ||
217 | 229 | ||
218 | return CONSTRAINT_NONE; | 230 | return CONSTRAINT_NONE; |
219 | } | 231 | } |
232 | #else | ||
233 | static enum oom_constraint constrained_alloc(struct zonelist *zonelist, | ||
234 | gfp_t gfp_mask, nodemask_t *nodemask) | ||
235 | { | ||
236 | return CONSTRAINT_NONE; | ||
237 | } | ||
238 | #endif | ||
220 | 239 | ||
221 | /* | 240 | /* |
222 | * Simple selection loop. We chose the process with the highest | 241 | * Simple selection loop. We chose the process with the highest |
@@ -337,7 +356,8 @@ static void dump_tasks(const struct mem_cgroup *mem) | |||
337 | } while_each_thread(g, p); | 356 | } while_each_thread(g, p); |
338 | } | 357 | } |
339 | 358 | ||
340 | static void dump_header(gfp_t gfp_mask, int order, struct mem_cgroup *mem) | 359 | static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, |
360 | struct mem_cgroup *mem) | ||
341 | { | 361 | { |
342 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " | 362 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " |
343 | "oom_adj=%d\n", | 363 | "oom_adj=%d\n", |
@@ -346,12 +366,14 @@ static void dump_header(gfp_t gfp_mask, int order, struct mem_cgroup *mem) | |||
346 | cpuset_print_task_mems_allowed(current); | 366 | cpuset_print_task_mems_allowed(current); |
347 | task_unlock(current); | 367 | task_unlock(current); |
348 | dump_stack(); | 368 | dump_stack(); |
349 | mem_cgroup_print_oom_info(mem, current); | 369 | mem_cgroup_print_oom_info(mem, p); |
350 | show_mem(); | 370 | show_mem(); |
351 | if (sysctl_oom_dump_tasks) | 371 | if (sysctl_oom_dump_tasks) |
352 | dump_tasks(mem); | 372 | dump_tasks(mem); |
353 | } | 373 | } |
354 | 374 | ||
375 | #define K(x) ((x) << (PAGE_SHIFT-10)) | ||
376 | |||
355 | /* | 377 | /* |
356 | * Send SIGKILL to the selected process irrespective of CAP_SYS_RAW_IO | 378 | * Send SIGKILL to the selected process irrespective of CAP_SYS_RAW_IO |
357 | * flag though it's unlikely that we select a process with CAP_SYS_RAW_IO | 379 | * flag though it's unlikely that we select a process with CAP_SYS_RAW_IO |
@@ -365,15 +387,23 @@ static void __oom_kill_task(struct task_struct *p, int verbose) | |||
365 | return; | 387 | return; |
366 | } | 388 | } |
367 | 389 | ||
390 | task_lock(p); | ||
368 | if (!p->mm) { | 391 | if (!p->mm) { |
369 | WARN_ON(1); | 392 | WARN_ON(1); |
370 | printk(KERN_WARNING "tried to kill an mm-less task!\n"); | 393 | printk(KERN_WARNING "tried to kill an mm-less task %d (%s)!\n", |
394 | task_pid_nr(p), p->comm); | ||
395 | task_unlock(p); | ||
371 | return; | 396 | return; |
372 | } | 397 | } |
373 | 398 | ||
374 | if (verbose) | 399 | if (verbose) |
375 | printk(KERN_ERR "Killed process %d (%s)\n", | 400 | printk(KERN_ERR "Killed process %d (%s) " |
376 | task_pid_nr(p), p->comm); | 401 | "vsz:%lukB, anon-rss:%lukB, file-rss:%lukB\n", |
402 | task_pid_nr(p), p->comm, | ||
403 | K(p->mm->total_vm), | ||
404 | K(get_mm_counter(p->mm, anon_rss)), | ||
405 | K(get_mm_counter(p->mm, file_rss))); | ||
406 | task_unlock(p); | ||
377 | 407 | ||
378 | /* | 408 | /* |
379 | * We give our sacrificial lamb high priority and access to | 409 | * We give our sacrificial lamb high priority and access to |
@@ -411,7 +441,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
411 | struct task_struct *c; | 441 | struct task_struct *c; |
412 | 442 | ||
413 | if (printk_ratelimit()) | 443 | if (printk_ratelimit()) |
414 | dump_header(gfp_mask, order, mem); | 444 | dump_header(p, gfp_mask, order, mem); |
415 | 445 | ||
416 | /* | 446 | /* |
417 | * If the task is already exiting, don't alarm the sysadmin or kill | 447 | * If the task is already exiting, don't alarm the sysadmin or kill |
@@ -547,7 +577,7 @@ retry: | |||
547 | /* Found nothing?!?! Either we hang forever, or we panic. */ | 577 | /* Found nothing?!?! Either we hang forever, or we panic. */ |
548 | if (!p) { | 578 | if (!p) { |
549 | read_unlock(&tasklist_lock); | 579 | read_unlock(&tasklist_lock); |
550 | dump_header(gfp_mask, order, NULL); | 580 | dump_header(NULL, gfp_mask, order, NULL); |
551 | panic("Out of memory and no killable processes...\n"); | 581 | panic("Out of memory and no killable processes...\n"); |
552 | } | 582 | } |
553 | 583 | ||
@@ -603,7 +633,8 @@ rest_and_return: | |||
603 | * OR try to be smart about which process to kill. Note that we | 633 | * OR try to be smart about which process to kill. Note that we |
604 | * don't have to be perfect here, we just have to be good. | 634 | * don't have to be perfect here, we just have to be good. |
605 | */ | 635 | */ |
606 | void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) | 636 | void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, |
637 | int order, nodemask_t *nodemask) | ||
607 | { | 638 | { |
608 | unsigned long freed = 0; | 639 | unsigned long freed = 0; |
609 | enum oom_constraint constraint; | 640 | enum oom_constraint constraint; |
@@ -614,7 +645,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) | |||
614 | return; | 645 | return; |
615 | 646 | ||
616 | if (sysctl_panic_on_oom == 2) { | 647 | if (sysctl_panic_on_oom == 2) { |
617 | dump_header(gfp_mask, order, NULL); | 648 | dump_header(NULL, gfp_mask, order, NULL); |
618 | panic("out of memory. Compulsory panic_on_oom is selected.\n"); | 649 | panic("out of memory. Compulsory panic_on_oom is selected.\n"); |
619 | } | 650 | } |
620 | 651 | ||
@@ -622,7 +653,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) | |||
622 | * Check if there were limitations on the allocation (only relevant for | 653 | * Check if there were limitations on the allocation (only relevant for |
623 | * NUMA) that may require different handling. | 654 | * NUMA) that may require different handling. |
624 | */ | 655 | */ |
625 | constraint = constrained_alloc(zonelist, gfp_mask); | 656 | constraint = constrained_alloc(zonelist, gfp_mask, nodemask); |
626 | read_lock(&tasklist_lock); | 657 | read_lock(&tasklist_lock); |
627 | 658 | ||
628 | switch (constraint) { | 659 | switch (constraint) { |
@@ -633,7 +664,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) | |||
633 | 664 | ||
634 | case CONSTRAINT_NONE: | 665 | case CONSTRAINT_NONE: |
635 | if (sysctl_panic_on_oom) { | 666 | if (sysctl_panic_on_oom) { |
636 | dump_header(gfp_mask, order, NULL); | 667 | dump_header(NULL, gfp_mask, order, NULL); |
637 | panic("out of memory. panic_on_oom is selected\n"); | 668 | panic("out of memory. panic_on_oom is selected\n"); |
638 | } | 669 | } |
639 | /* Fall-through */ | 670 | /* Fall-through */ |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 59d2e88fb47c..850c4a7e2fe5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1654,12 +1654,22 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | |||
1654 | if (page) | 1654 | if (page) |
1655 | goto out; | 1655 | goto out; |
1656 | 1656 | ||
1657 | /* The OOM killer will not help higher order allocs */ | 1657 | if (!(gfp_mask & __GFP_NOFAIL)) { |
1658 | if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_NOFAIL)) | 1658 | /* The OOM killer will not help higher order allocs */ |
1659 | goto out; | 1659 | if (order > PAGE_ALLOC_COSTLY_ORDER) |
1660 | 1660 | goto out; | |
1661 | /* | ||
1662 | * GFP_THISNODE contains __GFP_NORETRY and we never hit this. | ||
1663 | * Sanity check for bare calls of __GFP_THISNODE, not real OOM. | ||
1664 | * The caller should handle page allocation failure by itself if | ||
1665 | * it specifies __GFP_THISNODE. | ||
1666 | * Note: Hugepage uses it but will hit PAGE_ALLOC_COSTLY_ORDER. | ||
1667 | */ | ||
1668 | if (gfp_mask & __GFP_THISNODE) | ||
1669 | goto out; | ||
1670 | } | ||
1661 | /* Exhausted what can be done so it's blamo time */ | 1671 | /* Exhausted what can be done so it's blamo time */ |
1662 | out_of_memory(zonelist, gfp_mask, order); | 1672 | out_of_memory(zonelist, gfp_mask, order, nodemask); |
1663 | 1673 | ||
1664 | out: | 1674 | out: |
1665 | clear_zonelist_oom(zonelist, gfp_mask); | 1675 | clear_zonelist_oom(zonelist, gfp_mask); |
@@ -3123,7 +3133,7 @@ static int __cpuinit process_zones(int cpu) | |||
3123 | 3133 | ||
3124 | if (percpu_pagelist_fraction) | 3134 | if (percpu_pagelist_fraction) |
3125 | setup_pagelist_highmark(zone_pcp(zone, cpu), | 3135 | setup_pagelist_highmark(zone_pcp(zone, cpu), |
3126 | (zone->present_pages / percpu_pagelist_fraction)); | 3136 | (zone->present_pages / percpu_pagelist_fraction)); |
3127 | } | 3137 | } |
3128 | 3138 | ||
3129 | return 0; | 3139 | return 0; |
@@ -721,7 +721,7 @@ void page_add_file_rmap(struct page *page) | |||
721 | { | 721 | { |
722 | if (atomic_inc_and_test(&page->_mapcount)) { | 722 | if (atomic_inc_and_test(&page->_mapcount)) { |
723 | __inc_zone_page_state(page, NR_FILE_MAPPED); | 723 | __inc_zone_page_state(page, NR_FILE_MAPPED); |
724 | mem_cgroup_update_mapped_file_stat(page, 1); | 724 | mem_cgroup_update_file_mapped(page, 1); |
725 | } | 725 | } |
726 | } | 726 | } |
727 | 727 | ||
@@ -753,8 +753,8 @@ void page_remove_rmap(struct page *page) | |||
753 | __dec_zone_page_state(page, NR_ANON_PAGES); | 753 | __dec_zone_page_state(page, NR_ANON_PAGES); |
754 | } else { | 754 | } else { |
755 | __dec_zone_page_state(page, NR_FILE_MAPPED); | 755 | __dec_zone_page_state(page, NR_FILE_MAPPED); |
756 | mem_cgroup_update_file_mapped(page, -1); | ||
756 | } | 757 | } |
757 | mem_cgroup_update_mapped_file_stat(page, -1); | ||
758 | /* | 758 | /* |
759 | * It would be tidy to reset the PageAnon mapping here, | 759 | * It would be tidy to reset the PageAnon mapping here, |
760 | * but that might overwrite a racing page_add_anon_rmap | 760 | * but that might overwrite a racing page_add_anon_rmap |
diff --git a/mm/truncate.c b/mm/truncate.c index 2c147a7e5f2c..342deee22684 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -272,6 +272,7 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
272 | pagevec_release(&pvec); | 272 | pagevec_release(&pvec); |
273 | break; | 273 | break; |
274 | } | 274 | } |
275 | mem_cgroup_uncharge_start(); | ||
275 | for (i = 0; i < pagevec_count(&pvec); i++) { | 276 | for (i = 0; i < pagevec_count(&pvec); i++) { |
276 | struct page *page = pvec.pages[i]; | 277 | struct page *page = pvec.pages[i]; |
277 | 278 | ||
@@ -286,6 +287,7 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
286 | unlock_page(page); | 287 | unlock_page(page); |
287 | } | 288 | } |
288 | pagevec_release(&pvec); | 289 | pagevec_release(&pvec); |
290 | mem_cgroup_uncharge_end(); | ||
289 | } | 291 | } |
290 | } | 292 | } |
291 | EXPORT_SYMBOL(truncate_inode_pages_range); | 293 | EXPORT_SYMBOL(truncate_inode_pages_range); |
@@ -327,6 +329,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, | |||
327 | pagevec_init(&pvec, 0); | 329 | pagevec_init(&pvec, 0); |
328 | while (next <= end && | 330 | while (next <= end && |
329 | pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { | 331 | pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { |
332 | mem_cgroup_uncharge_start(); | ||
330 | for (i = 0; i < pagevec_count(&pvec); i++) { | 333 | for (i = 0; i < pagevec_count(&pvec); i++) { |
331 | struct page *page = pvec.pages[i]; | 334 | struct page *page = pvec.pages[i]; |
332 | pgoff_t index; | 335 | pgoff_t index; |
@@ -354,6 +357,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, | |||
354 | break; | 357 | break; |
355 | } | 358 | } |
356 | pagevec_release(&pvec); | 359 | pagevec_release(&pvec); |
360 | mem_cgroup_uncharge_end(); | ||
357 | cond_resched(); | 361 | cond_resched(); |
358 | } | 362 | } |
359 | return ret; | 363 | return ret; |
@@ -428,6 +432,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
428 | while (next <= end && !wrapped && | 432 | while (next <= end && !wrapped && |
429 | pagevec_lookup(&pvec, mapping, next, | 433 | pagevec_lookup(&pvec, mapping, next, |
430 | min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { | 434 | min(end - next, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) { |
435 | mem_cgroup_uncharge_start(); | ||
431 | for (i = 0; i < pagevec_count(&pvec); i++) { | 436 | for (i = 0; i < pagevec_count(&pvec); i++) { |
432 | struct page *page = pvec.pages[i]; | 437 | struct page *page = pvec.pages[i]; |
433 | pgoff_t page_index; | 438 | pgoff_t page_index; |
@@ -477,6 +482,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
477 | unlock_page(page); | 482 | unlock_page(page); |
478 | } | 483 | } |
479 | pagevec_release(&pvec); | 484 | pagevec_release(&pvec); |
485 | mem_cgroup_uncharge_end(); | ||
480 | cond_resched(); | 486 | cond_resched(); |
481 | } | 487 | } |
482 | return ret; | 488 | return ret; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bfa3e7865a8c..93c4e060c91e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -93,7 +93,7 @@ static int sock_pipe_buf_steal(struct pipe_inode_info *pipe, | |||
93 | 93 | ||
94 | 94 | ||
95 | /* Pipe buffer operations for a socket. */ | 95 | /* Pipe buffer operations for a socket. */ |
96 | static struct pipe_buf_operations sock_pipe_buf_ops = { | 96 | static const struct pipe_buf_operations sock_pipe_buf_ops = { |
97 | .can_merge = 0, | 97 | .can_merge = 0, |
98 | .map = generic_pipe_buf_map, | 98 | .map = generic_pipe_buf_map, |
99 | .unmap = generic_pipe_buf_unmap, | 99 | .unmap = generic_pipe_buf_unmap, |