Commit 7e0a16f6118a297dd467c1e5a0908429fcdf56af
1 parent
42d12f5aa1
Exists in
master
and in
4 other branches
V4L/DVB (10907): avoid loading the entire videodev.h header on V4L2 drivers
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 16 changed files with 27 additions and 27 deletions Inline Diff
- drivers/media/video/bt8xx/bttv.h
- drivers/media/video/bt8xx/bttvp.h
- drivers/media/video/cpia2/cpia2_v4l.c
- drivers/media/video/cx23885/cx23885-video.c
- drivers/media/video/cx88/cx88-video.c
- drivers/media/video/msp3400-driver.c
- drivers/media/video/ov7670.c
- drivers/media/video/saa7134/saa7134-video.c
- drivers/media/video/saa7146.h
- drivers/media/video/v4l2-ioctl.c
- drivers/media/video/vivi.c
- drivers/media/video/w9966.c
- drivers/media/video/w9968cf.c
- drivers/media/video/zoran/zoran_driver.c
- include/linux/videodev.h
- include/media/v4l2-ioctl.h
drivers/media/video/bt8xx/bttv.h
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * bttv - Bt848 frame grabber driver | 3 | * bttv - Bt848 frame grabber driver |
4 | * | 4 | * |
5 | * card ID's and external interfaces of the bttv driver | 5 | * card ID's and external interfaces of the bttv driver |
6 | * basically stuff needed by other drivers (i2c, lirc, ...) | 6 | * basically stuff needed by other drivers (i2c, lirc, ...) |
7 | * and is supported not to change much over time. | 7 | * and is supported not to change much over time. |
8 | * | 8 | * |
9 | * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) | 9 | * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) |
10 | * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> | 10 | * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #ifndef _BTTV_H_ | 14 | #ifndef _BTTV_H_ |
15 | #define _BTTV_H_ | 15 | #define _BTTV_H_ |
16 | 16 | ||
17 | #include <linux/videodev.h> | 17 | #include <linux/videodev2.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <media/ir-common.h> | 19 | #include <media/ir-common.h> |
20 | #include <media/ir-kbd-i2c.h> | 20 | #include <media/ir-kbd-i2c.h> |
21 | #include <media/i2c-addr.h> | 21 | #include <media/i2c-addr.h> |
22 | #include <media/tuner.h> | 22 | #include <media/tuner.h> |
23 | 23 | ||
24 | /* ---------------------------------------------------------- */ | 24 | /* ---------------------------------------------------------- */ |
25 | /* exported by bttv-cards.c */ | 25 | /* exported by bttv-cards.c */ |
26 | 26 | ||
27 | #define BTTV_BOARD_UNKNOWN 0x00 | 27 | #define BTTV_BOARD_UNKNOWN 0x00 |
28 | #define BTTV_BOARD_MIRO 0x01 | 28 | #define BTTV_BOARD_MIRO 0x01 |
29 | #define BTTV_BOARD_HAUPPAUGE 0x02 | 29 | #define BTTV_BOARD_HAUPPAUGE 0x02 |
30 | #define BTTV_BOARD_STB 0x03 | 30 | #define BTTV_BOARD_STB 0x03 |
31 | #define BTTV_BOARD_INTEL 0x04 | 31 | #define BTTV_BOARD_INTEL 0x04 |
32 | #define BTTV_BOARD_DIAMOND 0x05 | 32 | #define BTTV_BOARD_DIAMOND 0x05 |
33 | #define BTTV_BOARD_AVERMEDIA 0x06 | 33 | #define BTTV_BOARD_AVERMEDIA 0x06 |
34 | #define BTTV_BOARD_MATRIX_VISION 0x07 | 34 | #define BTTV_BOARD_MATRIX_VISION 0x07 |
35 | #define BTTV_BOARD_FLYVIDEO 0x08 | 35 | #define BTTV_BOARD_FLYVIDEO 0x08 |
36 | #define BTTV_BOARD_TURBOTV 0x09 | 36 | #define BTTV_BOARD_TURBOTV 0x09 |
37 | #define BTTV_BOARD_HAUPPAUGE878 0x0a | 37 | #define BTTV_BOARD_HAUPPAUGE878 0x0a |
38 | #define BTTV_BOARD_MIROPRO 0x0b | 38 | #define BTTV_BOARD_MIROPRO 0x0b |
39 | #define BTTV_BOARD_ADSTECH_TV 0x0c | 39 | #define BTTV_BOARD_ADSTECH_TV 0x0c |
40 | #define BTTV_BOARD_AVERMEDIA98 0x0d | 40 | #define BTTV_BOARD_AVERMEDIA98 0x0d |
41 | #define BTTV_BOARD_VHX 0x0e | 41 | #define BTTV_BOARD_VHX 0x0e |
42 | #define BTTV_BOARD_ZOLTRIX 0x0f | 42 | #define BTTV_BOARD_ZOLTRIX 0x0f |
43 | #define BTTV_BOARD_PIXVIEWPLAYTV 0x10 | 43 | #define BTTV_BOARD_PIXVIEWPLAYTV 0x10 |
44 | #define BTTV_BOARD_WINVIEW_601 0x11 | 44 | #define BTTV_BOARD_WINVIEW_601 0x11 |
45 | #define BTTV_BOARD_AVEC_INTERCAP 0x12 | 45 | #define BTTV_BOARD_AVEC_INTERCAP 0x12 |
46 | #define BTTV_BOARD_LIFE_FLYKIT 0x13 | 46 | #define BTTV_BOARD_LIFE_FLYKIT 0x13 |
47 | #define BTTV_BOARD_CEI_RAFFLES 0x14 | 47 | #define BTTV_BOARD_CEI_RAFFLES 0x14 |
48 | #define BTTV_BOARD_CONFERENCETV 0x15 | 48 | #define BTTV_BOARD_CONFERENCETV 0x15 |
49 | #define BTTV_BOARD_PHOEBE_TVMAS 0x16 | 49 | #define BTTV_BOARD_PHOEBE_TVMAS 0x16 |
50 | #define BTTV_BOARD_MODTEC_205 0x17 | 50 | #define BTTV_BOARD_MODTEC_205 0x17 |
51 | #define BTTV_BOARD_MAGICTVIEW061 0x18 | 51 | #define BTTV_BOARD_MAGICTVIEW061 0x18 |
52 | #define BTTV_BOARD_VOBIS_BOOSTAR 0x19 | 52 | #define BTTV_BOARD_VOBIS_BOOSTAR 0x19 |
53 | #define BTTV_BOARD_HAUPPAUG_WCAM 0x1a | 53 | #define BTTV_BOARD_HAUPPAUG_WCAM 0x1a |
54 | #define BTTV_BOARD_MAXI 0x1b | 54 | #define BTTV_BOARD_MAXI 0x1b |
55 | #define BTTV_BOARD_TERRATV 0x1c | 55 | #define BTTV_BOARD_TERRATV 0x1c |
56 | #define BTTV_BOARD_PXC200 0x1d | 56 | #define BTTV_BOARD_PXC200 0x1d |
57 | #define BTTV_BOARD_FLYVIDEO_98 0x1e | 57 | #define BTTV_BOARD_FLYVIDEO_98 0x1e |
58 | #define BTTV_BOARD_IPROTV 0x1f | 58 | #define BTTV_BOARD_IPROTV 0x1f |
59 | #define BTTV_BOARD_INTEL_C_S_PCI 0x20 | 59 | #define BTTV_BOARD_INTEL_C_S_PCI 0x20 |
60 | #define BTTV_BOARD_TERRATVALUE 0x21 | 60 | #define BTTV_BOARD_TERRATVALUE 0x21 |
61 | #define BTTV_BOARD_WINFAST2000 0x22 | 61 | #define BTTV_BOARD_WINFAST2000 0x22 |
62 | #define BTTV_BOARD_CHRONOS_VS2 0x23 | 62 | #define BTTV_BOARD_CHRONOS_VS2 0x23 |
63 | #define BTTV_BOARD_TYPHOON_TVIEW 0x24 | 63 | #define BTTV_BOARD_TYPHOON_TVIEW 0x24 |
64 | #define BTTV_BOARD_PXELVWPLTVPRO 0x25 | 64 | #define BTTV_BOARD_PXELVWPLTVPRO 0x25 |
65 | #define BTTV_BOARD_MAGICTVIEW063 0x26 | 65 | #define BTTV_BOARD_MAGICTVIEW063 0x26 |
66 | #define BTTV_BOARD_PINNACLE 0x27 | 66 | #define BTTV_BOARD_PINNACLE 0x27 |
67 | #define BTTV_BOARD_STB2 0x28 | 67 | #define BTTV_BOARD_STB2 0x28 |
68 | #define BTTV_BOARD_AVPHONE98 0x29 | 68 | #define BTTV_BOARD_AVPHONE98 0x29 |
69 | #define BTTV_BOARD_PV951 0x2a | 69 | #define BTTV_BOARD_PV951 0x2a |
70 | #define BTTV_BOARD_ONAIR_TV 0x2b | 70 | #define BTTV_BOARD_ONAIR_TV 0x2b |
71 | #define BTTV_BOARD_SIGMA_TVII_FM 0x2c | 71 | #define BTTV_BOARD_SIGMA_TVII_FM 0x2c |
72 | #define BTTV_BOARD_MATRIX_VISION2 0x2d | 72 | #define BTTV_BOARD_MATRIX_VISION2 0x2d |
73 | #define BTTV_BOARD_ZOLTRIX_GENIE 0x2e | 73 | #define BTTV_BOARD_ZOLTRIX_GENIE 0x2e |
74 | #define BTTV_BOARD_TERRATVRADIO 0x2f | 74 | #define BTTV_BOARD_TERRATVRADIO 0x2f |
75 | #define BTTV_BOARD_DYNALINK 0x30 | 75 | #define BTTV_BOARD_DYNALINK 0x30 |
76 | #define BTTV_BOARD_GVBCTV3PCI 0x31 | 76 | #define BTTV_BOARD_GVBCTV3PCI 0x31 |
77 | #define BTTV_BOARD_PXELVWPLTVPAK 0x32 | 77 | #define BTTV_BOARD_PXELVWPLTVPAK 0x32 |
78 | #define BTTV_BOARD_EAGLE 0x33 | 78 | #define BTTV_BOARD_EAGLE 0x33 |
79 | #define BTTV_BOARD_PINNACLEPRO 0x34 | 79 | #define BTTV_BOARD_PINNACLEPRO 0x34 |
80 | #define BTTV_BOARD_TVIEW_RDS_FM 0x35 | 80 | #define BTTV_BOARD_TVIEW_RDS_FM 0x35 |
81 | #define BTTV_BOARD_LIFETEC_9415 0x36 | 81 | #define BTTV_BOARD_LIFETEC_9415 0x36 |
82 | #define BTTV_BOARD_BESTBUY_EASYTV 0x37 | 82 | #define BTTV_BOARD_BESTBUY_EASYTV 0x37 |
83 | #define BTTV_BOARD_FLYVIDEO_98FM 0x38 | 83 | #define BTTV_BOARD_FLYVIDEO_98FM 0x38 |
84 | #define BTTV_BOARD_GRANDTEC 0x39 | 84 | #define BTTV_BOARD_GRANDTEC 0x39 |
85 | #define BTTV_BOARD_ASKEY_CPH060 0x3a | 85 | #define BTTV_BOARD_ASKEY_CPH060 0x3a |
86 | #define BTTV_BOARD_ASKEY_CPH03X 0x3b | 86 | #define BTTV_BOARD_ASKEY_CPH03X 0x3b |
87 | #define BTTV_BOARD_MM100PCTV 0x3c | 87 | #define BTTV_BOARD_MM100PCTV 0x3c |
88 | #define BTTV_BOARD_GMV1 0x3d | 88 | #define BTTV_BOARD_GMV1 0x3d |
89 | #define BTTV_BOARD_BESTBUY_EASYTV2 0x3e | 89 | #define BTTV_BOARD_BESTBUY_EASYTV2 0x3e |
90 | #define BTTV_BOARD_ATI_TVWONDER 0x3f | 90 | #define BTTV_BOARD_ATI_TVWONDER 0x3f |
91 | #define BTTV_BOARD_ATI_TVWONDERVE 0x40 | 91 | #define BTTV_BOARD_ATI_TVWONDERVE 0x40 |
92 | #define BTTV_BOARD_FLYVIDEO2000 0x41 | 92 | #define BTTV_BOARD_FLYVIDEO2000 0x41 |
93 | #define BTTV_BOARD_TERRATVALUER 0x42 | 93 | #define BTTV_BOARD_TERRATVALUER 0x42 |
94 | #define BTTV_BOARD_GVBCTV4PCI 0x43 | 94 | #define BTTV_BOARD_GVBCTV4PCI 0x43 |
95 | #define BTTV_BOARD_VOODOOTV_FM 0x44 | 95 | #define BTTV_BOARD_VOODOOTV_FM 0x44 |
96 | #define BTTV_BOARD_AIMMS 0x45 | 96 | #define BTTV_BOARD_AIMMS 0x45 |
97 | #define BTTV_BOARD_PV_BT878P_PLUS 0x46 | 97 | #define BTTV_BOARD_PV_BT878P_PLUS 0x46 |
98 | #define BTTV_BOARD_FLYVIDEO98EZ 0x47 | 98 | #define BTTV_BOARD_FLYVIDEO98EZ 0x47 |
99 | #define BTTV_BOARD_PV_BT878P_9B 0x48 | 99 | #define BTTV_BOARD_PV_BT878P_9B 0x48 |
100 | #define BTTV_BOARD_SENSORAY311 0x49 | 100 | #define BTTV_BOARD_SENSORAY311 0x49 |
101 | #define BTTV_BOARD_RV605 0x4a | 101 | #define BTTV_BOARD_RV605 0x4a |
102 | #define BTTV_BOARD_POWERCLR_MTV878 0x4b | 102 | #define BTTV_BOARD_POWERCLR_MTV878 0x4b |
103 | #define BTTV_BOARD_WINDVR 0x4c | 103 | #define BTTV_BOARD_WINDVR 0x4c |
104 | #define BTTV_BOARD_GRANDTEC_MULTI 0x4d | 104 | #define BTTV_BOARD_GRANDTEC_MULTI 0x4d |
105 | #define BTTV_BOARD_KWORLD 0x4e | 105 | #define BTTV_BOARD_KWORLD 0x4e |
106 | #define BTTV_BOARD_DSP_TCVIDEO 0x4f | 106 | #define BTTV_BOARD_DSP_TCVIDEO 0x4f |
107 | #define BTTV_BOARD_HAUPPAUGEPVR 0x50 | 107 | #define BTTV_BOARD_HAUPPAUGEPVR 0x50 |
108 | #define BTTV_BOARD_GVBCTV5PCI 0x51 | 108 | #define BTTV_BOARD_GVBCTV5PCI 0x51 |
109 | #define BTTV_BOARD_OSPREY1x0 0x52 | 109 | #define BTTV_BOARD_OSPREY1x0 0x52 |
110 | #define BTTV_BOARD_OSPREY1x0_848 0x53 | 110 | #define BTTV_BOARD_OSPREY1x0_848 0x53 |
111 | #define BTTV_BOARD_OSPREY101_848 0x54 | 111 | #define BTTV_BOARD_OSPREY101_848 0x54 |
112 | #define BTTV_BOARD_OSPREY1x1 0x55 | 112 | #define BTTV_BOARD_OSPREY1x1 0x55 |
113 | #define BTTV_BOARD_OSPREY1x1_SVID 0x56 | 113 | #define BTTV_BOARD_OSPREY1x1_SVID 0x56 |
114 | #define BTTV_BOARD_OSPREY2xx 0x57 | 114 | #define BTTV_BOARD_OSPREY2xx 0x57 |
115 | #define BTTV_BOARD_OSPREY2x0_SVID 0x58 | 115 | #define BTTV_BOARD_OSPREY2x0_SVID 0x58 |
116 | #define BTTV_BOARD_OSPREY2x0 0x59 | 116 | #define BTTV_BOARD_OSPREY2x0 0x59 |
117 | #define BTTV_BOARD_OSPREY500 0x5a | 117 | #define BTTV_BOARD_OSPREY500 0x5a |
118 | #define BTTV_BOARD_OSPREY540 0x5b | 118 | #define BTTV_BOARD_OSPREY540 0x5b |
119 | #define BTTV_BOARD_OSPREY2000 0x5c | 119 | #define BTTV_BOARD_OSPREY2000 0x5c |
120 | #define BTTV_BOARD_IDS_EAGLE 0x5d | 120 | #define BTTV_BOARD_IDS_EAGLE 0x5d |
121 | #define BTTV_BOARD_PINNACLESAT 0x5e | 121 | #define BTTV_BOARD_PINNACLESAT 0x5e |
122 | #define BTTV_BOARD_FORMAC_PROTV 0x5f | 122 | #define BTTV_BOARD_FORMAC_PROTV 0x5f |
123 | #define BTTV_BOARD_MACHTV 0x60 | 123 | #define BTTV_BOARD_MACHTV 0x60 |
124 | #define BTTV_BOARD_EURESYS_PICOLO 0x61 | 124 | #define BTTV_BOARD_EURESYS_PICOLO 0x61 |
125 | #define BTTV_BOARD_PV150 0x62 | 125 | #define BTTV_BOARD_PV150 0x62 |
126 | #define BTTV_BOARD_AD_TVK503 0x63 | 126 | #define BTTV_BOARD_AD_TVK503 0x63 |
127 | #define BTTV_BOARD_HERCULES_SM_TV 0x64 | 127 | #define BTTV_BOARD_HERCULES_SM_TV 0x64 |
128 | #define BTTV_BOARD_PACETV 0x65 | 128 | #define BTTV_BOARD_PACETV 0x65 |
129 | #define BTTV_BOARD_IVC200 0x66 | 129 | #define BTTV_BOARD_IVC200 0x66 |
130 | #define BTTV_BOARD_XGUARD 0x67 | 130 | #define BTTV_BOARD_XGUARD 0x67 |
131 | #define BTTV_BOARD_NEBULA_DIGITV 0x68 | 131 | #define BTTV_BOARD_NEBULA_DIGITV 0x68 |
132 | #define BTTV_BOARD_PV143 0x69 | 132 | #define BTTV_BOARD_PV143 0x69 |
133 | #define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a | 133 | #define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a |
134 | #define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b | 134 | #define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b |
135 | #define BTTV_BOARD_VD009_MINIDIN 0x6c | 135 | #define BTTV_BOARD_VD009_MINIDIN 0x6c |
136 | #define BTTV_BOARD_VD009_COMBI 0x6d | 136 | #define BTTV_BOARD_VD009_COMBI 0x6d |
137 | #define BTTV_BOARD_IVC100 0x6e | 137 | #define BTTV_BOARD_IVC100 0x6e |
138 | #define BTTV_BOARD_IVC120 0x6f | 138 | #define BTTV_BOARD_IVC120 0x6f |
139 | #define BTTV_BOARD_PC_HDTV 0x70 | 139 | #define BTTV_BOARD_PC_HDTV 0x70 |
140 | #define BTTV_BOARD_TWINHAN_DST 0x71 | 140 | #define BTTV_BOARD_TWINHAN_DST 0x71 |
141 | #define BTTV_BOARD_WINFASTVC100 0x72 | 141 | #define BTTV_BOARD_WINFASTVC100 0x72 |
142 | #define BTTV_BOARD_TEV560 0x73 | 142 | #define BTTV_BOARD_TEV560 0x73 |
143 | #define BTTV_BOARD_SIMUS_GVC1100 0x74 | 143 | #define BTTV_BOARD_SIMUS_GVC1100 0x74 |
144 | #define BTTV_BOARD_NGSTV_PLUS 0x75 | 144 | #define BTTV_BOARD_NGSTV_PLUS 0x75 |
145 | #define BTTV_BOARD_LMLBT4 0x76 | 145 | #define BTTV_BOARD_LMLBT4 0x76 |
146 | #define BTTV_BOARD_TEKRAM_M205 0x77 | 146 | #define BTTV_BOARD_TEKRAM_M205 0x77 |
147 | #define BTTV_BOARD_CONTVFMI 0x78 | 147 | #define BTTV_BOARD_CONTVFMI 0x78 |
148 | #define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 | 148 | #define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 |
149 | #define BTTV_BOARD_SPIRIT_TV 0x7a | 149 | #define BTTV_BOARD_SPIRIT_TV 0x7a |
150 | #define BTTV_BOARD_AVDVBT_771 0x7b | 150 | #define BTTV_BOARD_AVDVBT_771 0x7b |
151 | #define BTTV_BOARD_AVDVBT_761 0x7c | 151 | #define BTTV_BOARD_AVDVBT_761 0x7c |
152 | #define BTTV_BOARD_MATRIX_VISIONSQ 0x7d | 152 | #define BTTV_BOARD_MATRIX_VISIONSQ 0x7d |
153 | #define BTTV_BOARD_MATRIX_VISIONSLC 0x7e | 153 | #define BTTV_BOARD_MATRIX_VISIONSLC 0x7e |
154 | #define BTTV_BOARD_APAC_VIEWCOMP 0x7f | 154 | #define BTTV_BOARD_APAC_VIEWCOMP 0x7f |
155 | #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 | 155 | #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 |
156 | #define BTTV_BOARD_VGEAR_MYVCD 0x81 | 156 | #define BTTV_BOARD_VGEAR_MYVCD 0x81 |
157 | #define BTTV_BOARD_SUPER_TV 0x82 | 157 | #define BTTV_BOARD_SUPER_TV 0x82 |
158 | #define BTTV_BOARD_TIBET_CS16 0x83 | 158 | #define BTTV_BOARD_TIBET_CS16 0x83 |
159 | #define BTTV_BOARD_KODICOM_4400R 0x84 | 159 | #define BTTV_BOARD_KODICOM_4400R 0x84 |
160 | #define BTTV_BOARD_KODICOM_4400R_SL 0x85 | 160 | #define BTTV_BOARD_KODICOM_4400R_SL 0x85 |
161 | #define BTTV_BOARD_ADLINK_RTV24 0x86 | 161 | #define BTTV_BOARD_ADLINK_RTV24 0x86 |
162 | #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 | 162 | #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 |
163 | #define BTTV_BOARD_ACORP_Y878F 0x88 | 163 | #define BTTV_BOARD_ACORP_Y878F 0x88 |
164 | #define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 | 164 | #define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 |
165 | #define BTTV_BOARD_PV_BT878P_2E 0x8a | 165 | #define BTTV_BOARD_PV_BT878P_2E 0x8a |
166 | #define BTTV_BOARD_PV_M4900 0x8b | 166 | #define BTTV_BOARD_PV_M4900 0x8b |
167 | #define BTTV_BOARD_OSPREY440 0x8c | 167 | #define BTTV_BOARD_OSPREY440 0x8c |
168 | #define BTTV_BOARD_ASOUND_SKYEYE 0x8d | 168 | #define BTTV_BOARD_ASOUND_SKYEYE 0x8d |
169 | #define BTTV_BOARD_SABRENT_TVFM 0x8e | 169 | #define BTTV_BOARD_SABRENT_TVFM 0x8e |
170 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f | 170 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f |
171 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 | 171 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 |
172 | #define BTTV_BOARD_SSAI_SECURITY 0x91 | 172 | #define BTTV_BOARD_SSAI_SECURITY 0x91 |
173 | #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 | 173 | #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 |
174 | #define BTTV_BOARD_VOODOOTV_200 0x93 | 174 | #define BTTV_BOARD_VOODOOTV_200 0x93 |
175 | #define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 | 175 | #define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 |
176 | #define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 | 176 | #define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 |
177 | #define BTTV_BOARD_GEOVISION_GV600 0x96 | 177 | #define BTTV_BOARD_GEOVISION_GV600 0x96 |
178 | #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 | 178 | #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 |
179 | #define BTTV_BOARD_ENLTV_FM_2 0x98 | 179 | #define BTTV_BOARD_ENLTV_FM_2 0x98 |
180 | #define BTTV_BOARD_VD012 0x99 | 180 | #define BTTV_BOARD_VD012 0x99 |
181 | #define BTTV_BOARD_VD012_X1 0x9a | 181 | #define BTTV_BOARD_VD012_X1 0x9a |
182 | #define BTTV_BOARD_VD012_X2 0x9b | 182 | #define BTTV_BOARD_VD012_X2 0x9b |
183 | #define BTTV_BOARD_IVCE8784 0x9c | 183 | #define BTTV_BOARD_IVCE8784 0x9c |
184 | #define BTTV_BOARD_GEOVISION_GV800S 0x9d | 184 | #define BTTV_BOARD_GEOVISION_GV800S 0x9d |
185 | #define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e | 185 | #define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e |
186 | 186 | ||
187 | 187 | ||
188 | /* more card-specific defines */ | 188 | /* more card-specific defines */ |
189 | #define PT2254_L_CHANNEL 0x10 | 189 | #define PT2254_L_CHANNEL 0x10 |
190 | #define PT2254_R_CHANNEL 0x08 | 190 | #define PT2254_R_CHANNEL 0x08 |
191 | #define PT2254_DBS_IN_2 0x400 | 191 | #define PT2254_DBS_IN_2 0x400 |
192 | #define PT2254_DBS_IN_10 0x20000 | 192 | #define PT2254_DBS_IN_10 0x20000 |
193 | #define WINVIEW_PT2254_CLK 0x40 | 193 | #define WINVIEW_PT2254_CLK 0x40 |
194 | #define WINVIEW_PT2254_DATA 0x20 | 194 | #define WINVIEW_PT2254_DATA 0x20 |
195 | #define WINVIEW_PT2254_STROBE 0x80 | 195 | #define WINVIEW_PT2254_STROBE 0x80 |
196 | 196 | ||
197 | struct bttv_core { | 197 | struct bttv_core { |
198 | /* device structs */ | 198 | /* device structs */ |
199 | struct pci_dev *pci; | 199 | struct pci_dev *pci; |
200 | struct i2c_adapter i2c_adap; | 200 | struct i2c_adapter i2c_adap; |
201 | struct list_head subs; /* struct bttv_sub_device */ | 201 | struct list_head subs; /* struct bttv_sub_device */ |
202 | 202 | ||
203 | /* device config */ | 203 | /* device config */ |
204 | unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ | 204 | unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ |
205 | unsigned int type; /* card type (pointer into tvcards[]) */ | 205 | unsigned int type; /* card type (pointer into tvcards[]) */ |
206 | char name[8]; /* dev name */ | 206 | char name[8]; /* dev name */ |
207 | }; | 207 | }; |
208 | 208 | ||
209 | struct bttv; | 209 | struct bttv; |
210 | 210 | ||
211 | struct tvcard { | 211 | struct tvcard { |
212 | char *name; | 212 | char *name; |
213 | void (*volume_gpio)(struct bttv *btv, __u16 volume); | 213 | void (*volume_gpio)(struct bttv *btv, __u16 volume); |
214 | void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); | 214 | void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); |
215 | void (*muxsel_hook)(struct bttv *btv, unsigned int input); | 215 | void (*muxsel_hook)(struct bttv *btv, unsigned int input); |
216 | 216 | ||
217 | /* MUX bits for each input, two bits per input starting with the LSB */ | 217 | /* MUX bits for each input, two bits per input starting with the LSB */ |
218 | u32 muxsel; /* Use MUXSEL() to set */ | 218 | u32 muxsel; /* Use MUXSEL() to set */ |
219 | 219 | ||
220 | u32 gpiomask; | 220 | u32 gpiomask; |
221 | u32 gpiomux[4]; /* Tuner, Radio, external, internal */ | 221 | u32 gpiomux[4]; /* Tuner, Radio, external, internal */ |
222 | u32 gpiomute; /* GPIO mute setting */ | 222 | u32 gpiomute; /* GPIO mute setting */ |
223 | u32 gpiomask2; /* GPIO MUX mask */ | 223 | u32 gpiomask2; /* GPIO MUX mask */ |
224 | 224 | ||
225 | unsigned int tuner_type; | 225 | unsigned int tuner_type; |
226 | u8 tuner_addr; | 226 | u8 tuner_addr; |
227 | u8 video_inputs; /* Number of inputs */ | 227 | u8 video_inputs; /* Number of inputs */ |
228 | unsigned int svhs:4; /* Which input is s-video */ | 228 | unsigned int svhs:4; /* Which input is s-video */ |
229 | #define NO_SVHS 15 | 229 | #define NO_SVHS 15 |
230 | unsigned int pll:2; | 230 | unsigned int pll:2; |
231 | #define PLL_NONE 0 | 231 | #define PLL_NONE 0 |
232 | #define PLL_28 1 | 232 | #define PLL_28 1 |
233 | #define PLL_35 2 | 233 | #define PLL_35 2 |
234 | 234 | ||
235 | /* i2c audio flags */ | 235 | /* i2c audio flags */ |
236 | unsigned int no_msp34xx:1; | 236 | unsigned int no_msp34xx:1; |
237 | unsigned int no_tda9875:1; | 237 | unsigned int no_tda9875:1; |
238 | unsigned int no_tda7432:1; | 238 | unsigned int no_tda7432:1; |
239 | unsigned int needs_tvaudio:1; | 239 | unsigned int needs_tvaudio:1; |
240 | unsigned int msp34xx_alt:1; | 240 | unsigned int msp34xx_alt:1; |
241 | 241 | ||
242 | unsigned int no_video:1; /* video pci function is unused */ | 242 | unsigned int no_video:1; /* video pci function is unused */ |
243 | unsigned int has_dvb:1; | 243 | unsigned int has_dvb:1; |
244 | unsigned int has_remote:1; | 244 | unsigned int has_remote:1; |
245 | unsigned int has_radio:1; | 245 | unsigned int has_radio:1; |
246 | unsigned int has_dig_in:1; /* Has digital input (always last input) */ | 246 | unsigned int has_dig_in:1; /* Has digital input (always last input) */ |
247 | unsigned int no_gpioirq:1; | 247 | unsigned int no_gpioirq:1; |
248 | }; | 248 | }; |
249 | 249 | ||
250 | extern struct tvcard bttv_tvcards[]; | 250 | extern struct tvcard bttv_tvcards[]; |
251 | 251 | ||
252 | /* | 252 | /* |
253 | * This bit of cpp voodoo is used to create a macro with a variable number of | 253 | * This bit of cpp voodoo is used to create a macro with a variable number of |
254 | * arguments (1 to 16). It will pack each argument into a word two bits at a | 254 | * arguments (1 to 16). It will pack each argument into a word two bits at a |
255 | * time. It can't be a function because it needs to be compile time constant to | 255 | * time. It can't be a function because it needs to be compile time constant to |
256 | * initialize structures. Since each argument must fit in two bits, it's ok | 256 | * initialize structures. Since each argument must fit in two bits, it's ok |
257 | * that they are changed to octal. One should not use hex number, macros, or | 257 | * that they are changed to octal. One should not use hex number, macros, or |
258 | * anything else with this macro. Just use plain integers from 0 to 3. | 258 | * anything else with this macro. Just use plain integers from 0 to 3. |
259 | */ | 259 | */ |
260 | #define _MUXSELf(a) 0##a << 30 | 260 | #define _MUXSELf(a) 0##a << 30 |
261 | #define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) | 261 | #define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) |
262 | #define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) | 262 | #define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) |
263 | #define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) | 263 | #define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) |
264 | #define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) | 264 | #define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) |
265 | #define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) | 265 | #define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) |
266 | #define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) | 266 | #define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) |
267 | #define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) | 267 | #define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) |
268 | #define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) | 268 | #define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) |
269 | #define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) | 269 | #define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) |
270 | #define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) | 270 | #define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) |
271 | #define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) | 271 | #define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) |
272 | #define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) | 272 | #define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) |
273 | #define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) | 273 | #define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) |
274 | #define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) | 274 | #define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) |
275 | #define MUXSEL(a, b...) (a | _MUXSEL1(b)) | 275 | #define MUXSEL(a, b...) (a | _MUXSEL1(b)) |
276 | 276 | ||
277 | /* identification / initialization of the card */ | 277 | /* identification / initialization of the card */ |
278 | extern void bttv_idcard(struct bttv *btv); | 278 | extern void bttv_idcard(struct bttv *btv); |
279 | extern void bttv_init_card1(struct bttv *btv); | 279 | extern void bttv_init_card1(struct bttv *btv); |
280 | extern void bttv_init_card2(struct bttv *btv); | 280 | extern void bttv_init_card2(struct bttv *btv); |
281 | 281 | ||
282 | /* card-specific funtions */ | 282 | /* card-specific funtions */ |
283 | extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); | 283 | extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); |
284 | extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); | 284 | extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); |
285 | 285 | ||
286 | /* extra tweaks for some chipsets */ | 286 | /* extra tweaks for some chipsets */ |
287 | extern void bttv_check_chipset(void); | 287 | extern void bttv_check_chipset(void); |
288 | extern int bttv_handle_chipset(struct bttv *btv); | 288 | extern int bttv_handle_chipset(struct bttv *btv); |
289 | 289 | ||
290 | /* ---------------------------------------------------------- */ | 290 | /* ---------------------------------------------------------- */ |
291 | /* exported by bttv-if.c */ | 291 | /* exported by bttv-if.c */ |
292 | 292 | ||
293 | /* this obsolete -- please use the sysfs-based | 293 | /* this obsolete -- please use the sysfs-based |
294 | interface below for new code */ | 294 | interface below for new code */ |
295 | 295 | ||
296 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); | 296 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); |
297 | 297 | ||
298 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: | 298 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: |
299 | data | (current_GPOE_value & ~mask) | 299 | data | (current_GPOE_value & ~mask) |
300 | returns negative value if error occurred | 300 | returns negative value if error occurred |
301 | */ | 301 | */ |
302 | extern int bttv_gpio_enable(unsigned int card, | 302 | extern int bttv_gpio_enable(unsigned int card, |
303 | unsigned long mask, unsigned long data); | 303 | unsigned long mask, unsigned long data); |
304 | 304 | ||
305 | /* fills data with GPDATA register contents | 305 | /* fills data with GPDATA register contents |
306 | returns negative value if error occurred | 306 | returns negative value if error occurred |
307 | */ | 307 | */ |
308 | extern int bttv_read_gpio(unsigned int card, unsigned long *data); | 308 | extern int bttv_read_gpio(unsigned int card, unsigned long *data); |
309 | 309 | ||
310 | /* sets GPDATA register to new value: | 310 | /* sets GPDATA register to new value: |
311 | (data & mask) | (current_GPDATA_value & ~mask) | 311 | (data & mask) | (current_GPDATA_value & ~mask) |
312 | returns negative value if error occurred | 312 | returns negative value if error occurred |
313 | */ | 313 | */ |
314 | extern int bttv_write_gpio(unsigned int card, | 314 | extern int bttv_write_gpio(unsigned int card, |
315 | unsigned long mask, unsigned long data); | 315 | unsigned long mask, unsigned long data); |
316 | 316 | ||
317 | 317 | ||
318 | 318 | ||
319 | 319 | ||
320 | /* ---------------------------------------------------------- */ | 320 | /* ---------------------------------------------------------- */ |
321 | /* sysfs/driver-moded based gpio access interface */ | 321 | /* sysfs/driver-moded based gpio access interface */ |
322 | 322 | ||
323 | struct bttv_sub_device { | 323 | struct bttv_sub_device { |
324 | struct device dev; | 324 | struct device dev; |
325 | struct bttv_core *core; | 325 | struct bttv_core *core; |
326 | struct list_head list; | 326 | struct list_head list; |
327 | }; | 327 | }; |
328 | #define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) | 328 | #define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) |
329 | 329 | ||
330 | struct bttv_sub_driver { | 330 | struct bttv_sub_driver { |
331 | struct device_driver drv; | 331 | struct device_driver drv; |
332 | char wanted[20]; | 332 | char wanted[20]; |
333 | int (*probe)(struct bttv_sub_device *sub); | 333 | int (*probe)(struct bttv_sub_device *sub); |
334 | void (*remove)(struct bttv_sub_device *sub); | 334 | void (*remove)(struct bttv_sub_device *sub); |
335 | }; | 335 | }; |
336 | #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) | 336 | #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) |
337 | 337 | ||
338 | int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); | 338 | int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); |
339 | int bttv_sub_unregister(struct bttv_sub_driver *drv); | 339 | int bttv_sub_unregister(struct bttv_sub_driver *drv); |
340 | 340 | ||
341 | /* gpio access functions */ | 341 | /* gpio access functions */ |
342 | void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); | 342 | void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); |
343 | u32 bttv_gpio_read(struct bttv_core *core); | 343 | u32 bttv_gpio_read(struct bttv_core *core); |
344 | void bttv_gpio_write(struct bttv_core *core, u32 value); | 344 | void bttv_gpio_write(struct bttv_core *core, u32 value); |
345 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); | 345 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); |
346 | 346 | ||
347 | #define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) | 347 | #define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) |
348 | #define gpio_read() bttv_gpio_read(&btv->c) | 348 | #define gpio_read() bttv_gpio_read(&btv->c) |
349 | #define gpio_write(value) bttv_gpio_write(&btv->c, value) | 349 | #define gpio_write(value) bttv_gpio_write(&btv->c, value) |
350 | #define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) | 350 | #define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) |
351 | 351 | ||
352 | 352 | ||
353 | /* ---------------------------------------------------------- */ | 353 | /* ---------------------------------------------------------- */ |
354 | /* i2c */ | 354 | /* i2c */ |
355 | 355 | ||
356 | extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); | 356 | extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); |
357 | extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); | 357 | extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); |
358 | extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, | 358 | extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, |
359 | unsigned char b2, int both); | 359 | unsigned char b2, int both); |
360 | extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); | 360 | extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); |
361 | 361 | ||
362 | extern int bttv_input_init(struct bttv *dev); | 362 | extern int bttv_input_init(struct bttv *dev); |
363 | extern void bttv_input_fini(struct bttv *dev); | 363 | extern void bttv_input_fini(struct bttv *dev); |
364 | extern void bttv_input_irq(struct bttv *dev); | 364 | extern void bttv_input_irq(struct bttv *dev); |
365 | 365 | ||
366 | #endif /* _BTTV_H_ */ | 366 | #endif /* _BTTV_H_ */ |
367 | /* | 367 | /* |
368 | * Local variables: | 368 | * Local variables: |
369 | * c-basic-offset: 8 | 369 | * c-basic-offset: 8 |
370 | * End: | 370 | * End: |
371 | */ | 371 | */ |
372 | 372 |
drivers/media/video/bt8xx/bttvp.h
1 | /* | 1 | /* |
2 | 2 | ||
3 | bttv - Bt848 frame grabber driver | 3 | bttv - Bt848 frame grabber driver |
4 | 4 | ||
5 | bttv's *private* header file -- nobody other than bttv itself | 5 | bttv's *private* header file -- nobody other than bttv itself |
6 | should ever include this file. | 6 | should ever include this file. |
7 | 7 | ||
8 | (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org> | 8 | (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org> |
9 | 9 | ||
10 | This program is free software; you can redistribute it and/or modify | 10 | This program is free software; you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License as published by | 11 | it under the terms of the GNU General Public License as published by |
12 | the Free Software Foundation; either version 2 of the License, or | 12 | the Free Software Foundation; either version 2 of the License, or |
13 | (at your option) any later version. | 13 | (at your option) any later version. |
14 | 14 | ||
15 | This program is distributed in the hope that it will be useful, | 15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | GNU General Public License for more details. | 18 | GNU General Public License for more details. |
19 | 19 | ||
20 | You should have received a copy of the GNU General Public License | 20 | You should have received a copy of the GNU General Public License |
21 | along with this program; if not, write to the Free Software | 21 | along with this program; if not, write to the Free Software |
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #ifndef _BTTVP_H_ | 25 | #ifndef _BTTVP_H_ |
26 | #define _BTTVP_H_ | 26 | #define _BTTVP_H_ |
27 | 27 | ||
28 | #include <linux/version.h> | 28 | #include <linux/version.h> |
29 | #define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17) | 29 | #define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17) |
30 | 30 | ||
31 | #include <linux/types.h> | 31 | #include <linux/types.h> |
32 | #include <linux/wait.h> | 32 | #include <linux/wait.h> |
33 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
34 | #include <linux/i2c-algo-bit.h> | 34 | #include <linux/i2c-algo-bit.h> |
35 | #include <linux/videodev.h> | ||
36 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
37 | #include <linux/input.h> | 36 | #include <linux/input.h> |
38 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
39 | #include <linux/scatterlist.h> | 38 | #include <linux/scatterlist.h> |
40 | #include <asm/io.h> | 39 | #include <asm/io.h> |
41 | #include <media/v4l2-common.h> | 40 | #include <media/v4l2-common.h> |
42 | #include <linux/device.h> | 41 | #include <linux/device.h> |
43 | #include <media/videobuf-dma-sg.h> | 42 | #include <media/videobuf-dma-sg.h> |
44 | #include <media/tveeprom.h> | 43 | #include <media/tveeprom.h> |
45 | #include <media/ir-common.h> | 44 | #include <media/ir-common.h> |
46 | 45 | ||
47 | 46 | ||
48 | #include "bt848.h" | 47 | #include "bt848.h" |
49 | #include "bttv.h" | 48 | #include "bttv.h" |
50 | #include "btcx-risc.h" | 49 | #include "btcx-risc.h" |
51 | 50 | ||
52 | #ifdef __KERNEL__ | 51 | #ifdef __KERNEL__ |
53 | 52 | ||
54 | #define FORMAT_FLAGS_DITHER 0x01 | 53 | #define FORMAT_FLAGS_DITHER 0x01 |
55 | #define FORMAT_FLAGS_PACKED 0x02 | 54 | #define FORMAT_FLAGS_PACKED 0x02 |
56 | #define FORMAT_FLAGS_PLANAR 0x04 | 55 | #define FORMAT_FLAGS_PLANAR 0x04 |
57 | #define FORMAT_FLAGS_RAW 0x08 | 56 | #define FORMAT_FLAGS_RAW 0x08 |
58 | #define FORMAT_FLAGS_CrCb 0x10 | 57 | #define FORMAT_FLAGS_CrCb 0x10 |
59 | 58 | ||
60 | #define RISC_SLOT_O_VBI 4 | 59 | #define RISC_SLOT_O_VBI 4 |
61 | #define RISC_SLOT_O_FIELD 6 | 60 | #define RISC_SLOT_O_FIELD 6 |
62 | #define RISC_SLOT_E_VBI 10 | 61 | #define RISC_SLOT_E_VBI 10 |
63 | #define RISC_SLOT_E_FIELD 12 | 62 | #define RISC_SLOT_E_FIELD 12 |
64 | #define RISC_SLOT_LOOP 14 | 63 | #define RISC_SLOT_LOOP 14 |
65 | 64 | ||
66 | #define RESOURCE_OVERLAY 1 | 65 | #define RESOURCE_OVERLAY 1 |
67 | #define RESOURCE_VIDEO_STREAM 2 | 66 | #define RESOURCE_VIDEO_STREAM 2 |
68 | #define RESOURCE_VBI 4 | 67 | #define RESOURCE_VBI 4 |
69 | #define RESOURCE_VIDEO_READ 8 | 68 | #define RESOURCE_VIDEO_READ 8 |
70 | 69 | ||
71 | #define RAW_LINES 640 | 70 | #define RAW_LINES 640 |
72 | #define RAW_BPL 1024 | 71 | #define RAW_BPL 1024 |
73 | 72 | ||
74 | #define UNSET (-1U) | 73 | #define UNSET (-1U) |
75 | 74 | ||
76 | /* Min. value in VDELAY register. */ | 75 | /* Min. value in VDELAY register. */ |
77 | #define MIN_VDELAY 2 | 76 | #define MIN_VDELAY 2 |
78 | /* Even to get Cb first, odd for Cr. */ | 77 | /* Even to get Cb first, odd for Cr. */ |
79 | #define MAX_HDELAY (0x3FF & -2) | 78 | #define MAX_HDELAY (0x3FF & -2) |
80 | /* Limits scaled width, which must be a multiple of 4. */ | 79 | /* Limits scaled width, which must be a multiple of 4. */ |
81 | #define MAX_HACTIVE (0x3FF & -4) | 80 | #define MAX_HACTIVE (0x3FF & -4) |
82 | 81 | ||
83 | #define BTTV_NORMS (\ | 82 | #define BTTV_NORMS (\ |
84 | V4L2_STD_PAL | V4L2_STD_PAL_N | \ | 83 | V4L2_STD_PAL | V4L2_STD_PAL_N | \ |
85 | V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ | 84 | V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ |
86 | V4L2_STD_NTSC | V4L2_STD_PAL_M | \ | 85 | V4L2_STD_NTSC | V4L2_STD_PAL_M | \ |
87 | V4L2_STD_PAL_60) | 86 | V4L2_STD_PAL_60) |
88 | /* ---------------------------------------------------------- */ | 87 | /* ---------------------------------------------------------- */ |
89 | 88 | ||
90 | struct bttv_tvnorm { | 89 | struct bttv_tvnorm { |
91 | int v4l2_id; | 90 | int v4l2_id; |
92 | char *name; | 91 | char *name; |
93 | u32 Fsc; | 92 | u32 Fsc; |
94 | u16 swidth, sheight; /* scaled standard width, height */ | 93 | u16 swidth, sheight; /* scaled standard width, height */ |
95 | u16 totalwidth; | 94 | u16 totalwidth; |
96 | u8 adelay, bdelay, iform; | 95 | u8 adelay, bdelay, iform; |
97 | u32 scaledtwidth; | 96 | u32 scaledtwidth; |
98 | u16 hdelayx1, hactivex1; | 97 | u16 hdelayx1, hactivex1; |
99 | u16 vdelay; | 98 | u16 vdelay; |
100 | u8 vbipack; | 99 | u8 vbipack; |
101 | u16 vtotal; | 100 | u16 vtotal; |
102 | int sram; | 101 | int sram; |
103 | /* ITU-R frame line number of the first VBI line we can | 102 | /* ITU-R frame line number of the first VBI line we can |
104 | capture, of the first and second field. The last possible line | 103 | capture, of the first and second field. The last possible line |
105 | is determined by cropcap.bounds. */ | 104 | is determined by cropcap.bounds. */ |
106 | u16 vbistart[2]; | 105 | u16 vbistart[2]; |
107 | /* Horizontally this counts fCLKx1 samples following the leading | 106 | /* Horizontally this counts fCLKx1 samples following the leading |
108 | edge of the horizontal sync pulse, vertically ITU-R frame line | 107 | edge of the horizontal sync pulse, vertically ITU-R frame line |
109 | numbers of the first field times two (2, 4, 6, ... 524 or 624). */ | 108 | numbers of the first field times two (2, 4, 6, ... 524 or 624). */ |
110 | struct v4l2_cropcap cropcap; | 109 | struct v4l2_cropcap cropcap; |
111 | }; | 110 | }; |
112 | extern const struct bttv_tvnorm bttv_tvnorms[]; | 111 | extern const struct bttv_tvnorm bttv_tvnorms[]; |
113 | 112 | ||
114 | struct bttv_format { | 113 | struct bttv_format { |
115 | char *name; | 114 | char *name; |
116 | int fourcc; /* video4linux 2 */ | 115 | int fourcc; /* video4linux 2 */ |
117 | int btformat; /* BT848_COLOR_FMT_* */ | 116 | int btformat; /* BT848_COLOR_FMT_* */ |
118 | int btswap; /* BT848_COLOR_CTL_* */ | 117 | int btswap; /* BT848_COLOR_CTL_* */ |
119 | int depth; /* bit/pixel */ | 118 | int depth; /* bit/pixel */ |
120 | int flags; | 119 | int flags; |
121 | int hshift,vshift; /* for planar modes */ | 120 | int hshift,vshift; /* for planar modes */ |
122 | }; | 121 | }; |
123 | 122 | ||
124 | /* ---------------------------------------------------------- */ | 123 | /* ---------------------------------------------------------- */ |
125 | 124 | ||
126 | struct bttv_geometry { | 125 | struct bttv_geometry { |
127 | u8 vtc,crop,comb; | 126 | u8 vtc,crop,comb; |
128 | u16 width,hscale,hdelay; | 127 | u16 width,hscale,hdelay; |
129 | u16 sheight,vscale,vdelay,vtotal; | 128 | u16 sheight,vscale,vdelay,vtotal; |
130 | }; | 129 | }; |
131 | 130 | ||
132 | struct bttv_buffer { | 131 | struct bttv_buffer { |
133 | /* common v4l buffer stuff -- must be first */ | 132 | /* common v4l buffer stuff -- must be first */ |
134 | struct videobuf_buffer vb; | 133 | struct videobuf_buffer vb; |
135 | 134 | ||
136 | /* bttv specific */ | 135 | /* bttv specific */ |
137 | const struct bttv_format *fmt; | 136 | const struct bttv_format *fmt; |
138 | unsigned int tvnorm; | 137 | unsigned int tvnorm; |
139 | int btformat; | 138 | int btformat; |
140 | int btswap; | 139 | int btswap; |
141 | struct bttv_geometry geo; | 140 | struct bttv_geometry geo; |
142 | struct btcx_riscmem top; | 141 | struct btcx_riscmem top; |
143 | struct btcx_riscmem bottom; | 142 | struct btcx_riscmem bottom; |
144 | struct v4l2_rect crop; | 143 | struct v4l2_rect crop; |
145 | unsigned int vbi_skip[2]; | 144 | unsigned int vbi_skip[2]; |
146 | unsigned int vbi_count[2]; | 145 | unsigned int vbi_count[2]; |
147 | }; | 146 | }; |
148 | 147 | ||
149 | struct bttv_buffer_set { | 148 | struct bttv_buffer_set { |
150 | struct bttv_buffer *top; /* top field buffer */ | 149 | struct bttv_buffer *top; /* top field buffer */ |
151 | struct bttv_buffer *bottom; /* bottom field buffer */ | 150 | struct bttv_buffer *bottom; /* bottom field buffer */ |
152 | unsigned int top_irq; | 151 | unsigned int top_irq; |
153 | unsigned int frame_irq; | 152 | unsigned int frame_irq; |
154 | }; | 153 | }; |
155 | 154 | ||
156 | struct bttv_overlay { | 155 | struct bttv_overlay { |
157 | unsigned int tvnorm; | 156 | unsigned int tvnorm; |
158 | struct v4l2_rect w; | 157 | struct v4l2_rect w; |
159 | enum v4l2_field field; | 158 | enum v4l2_field field; |
160 | struct v4l2_clip *clips; | 159 | struct v4l2_clip *clips; |
161 | int nclips; | 160 | int nclips; |
162 | int setup_ok; | 161 | int setup_ok; |
163 | }; | 162 | }; |
164 | 163 | ||
165 | struct bttv_vbi_fmt { | 164 | struct bttv_vbi_fmt { |
166 | struct v4l2_vbi_format fmt; | 165 | struct v4l2_vbi_format fmt; |
167 | 166 | ||
168 | /* fmt.start[] and count[] refer to this video standard. */ | 167 | /* fmt.start[] and count[] refer to this video standard. */ |
169 | const struct bttv_tvnorm *tvnorm; | 168 | const struct bttv_tvnorm *tvnorm; |
170 | 169 | ||
171 | /* Earliest possible start of video capturing with this | 170 | /* Earliest possible start of video capturing with this |
172 | v4l2_vbi_format, in struct bttv_crop.rect units. */ | 171 | v4l2_vbi_format, in struct bttv_crop.rect units. */ |
173 | __s32 end; | 172 | __s32 end; |
174 | }; | 173 | }; |
175 | 174 | ||
176 | /* bttv-vbi.c */ | 175 | /* bttv-vbi.c */ |
177 | void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); | 176 | void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); |
178 | 177 | ||
179 | struct bttv_crop { | 178 | struct bttv_crop { |
180 | /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ | 179 | /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ |
181 | struct v4l2_rect rect; | 180 | struct v4l2_rect rect; |
182 | 181 | ||
183 | /* Scaled image size limits with this crop rect. Divide | 182 | /* Scaled image size limits with this crop rect. Divide |
184 | max_height, but not min_height, by two when capturing | 183 | max_height, but not min_height, by two when capturing |
185 | single fields. See also bttv_crop_reset() and | 184 | single fields. See also bttv_crop_reset() and |
186 | bttv_crop_adjust() in bttv-driver.c. */ | 185 | bttv_crop_adjust() in bttv-driver.c. */ |
187 | __s32 min_scaled_width; | 186 | __s32 min_scaled_width; |
188 | __s32 min_scaled_height; | 187 | __s32 min_scaled_height; |
189 | __s32 max_scaled_width; | 188 | __s32 max_scaled_width; |
190 | __s32 max_scaled_height; | 189 | __s32 max_scaled_height; |
191 | }; | 190 | }; |
192 | 191 | ||
193 | struct bttv_fh { | 192 | struct bttv_fh { |
194 | struct bttv *btv; | 193 | struct bttv *btv; |
195 | int resources; | 194 | int resources; |
196 | #ifdef VIDIOC_G_PRIORITY | 195 | #ifdef VIDIOC_G_PRIORITY |
197 | enum v4l2_priority prio; | 196 | enum v4l2_priority prio; |
198 | #endif | 197 | #endif |
199 | enum v4l2_buf_type type; | 198 | enum v4l2_buf_type type; |
200 | 199 | ||
201 | /* video capture */ | 200 | /* video capture */ |
202 | struct videobuf_queue cap; | 201 | struct videobuf_queue cap; |
203 | const struct bttv_format *fmt; | 202 | const struct bttv_format *fmt; |
204 | int width; | 203 | int width; |
205 | int height; | 204 | int height; |
206 | 205 | ||
207 | /* video overlay */ | 206 | /* video overlay */ |
208 | const struct bttv_format *ovfmt; | 207 | const struct bttv_format *ovfmt; |
209 | struct bttv_overlay ov; | 208 | struct bttv_overlay ov; |
210 | 209 | ||
211 | /* Application called VIDIOC_S_CROP. */ | 210 | /* Application called VIDIOC_S_CROP. */ |
212 | int do_crop; | 211 | int do_crop; |
213 | 212 | ||
214 | /* vbi capture */ | 213 | /* vbi capture */ |
215 | struct videobuf_queue vbi; | 214 | struct videobuf_queue vbi; |
216 | /* Current VBI capture window as seen through this fh (cannot | 215 | /* Current VBI capture window as seen through this fh (cannot |
217 | be global for compatibility with earlier drivers). Protected | 216 | be global for compatibility with earlier drivers). Protected |
218 | by struct bttv.lock and struct bttv_fh.vbi.lock. */ | 217 | by struct bttv.lock and struct bttv_fh.vbi.lock. */ |
219 | struct bttv_vbi_fmt vbi_fmt; | 218 | struct bttv_vbi_fmt vbi_fmt; |
220 | }; | 219 | }; |
221 | 220 | ||
222 | /* ---------------------------------------------------------- */ | 221 | /* ---------------------------------------------------------- */ |
223 | /* bttv-risc.c */ | 222 | /* bttv-risc.c */ |
224 | 223 | ||
225 | /* risc code generators - capture */ | 224 | /* risc code generators - capture */ |
226 | int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, | 225 | int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, |
227 | struct scatterlist *sglist, | 226 | struct scatterlist *sglist, |
228 | unsigned int offset, unsigned int bpl, | 227 | unsigned int offset, unsigned int bpl, |
229 | unsigned int pitch, unsigned int skip_lines, | 228 | unsigned int pitch, unsigned int skip_lines, |
230 | unsigned int store_lines); | 229 | unsigned int store_lines); |
231 | 230 | ||
232 | /* control dma register + risc main loop */ | 231 | /* control dma register + risc main loop */ |
233 | void bttv_set_dma(struct bttv *btv, int override); | 232 | void bttv_set_dma(struct bttv *btv, int override); |
234 | int bttv_risc_init_main(struct bttv *btv); | 233 | int bttv_risc_init_main(struct bttv *btv); |
235 | int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, | 234 | int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, |
236 | int irqflags); | 235 | int irqflags); |
237 | 236 | ||
238 | /* capture buffer handling */ | 237 | /* capture buffer handling */ |
239 | int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); | 238 | int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); |
240 | int bttv_buffer_activate_video(struct bttv *btv, | 239 | int bttv_buffer_activate_video(struct bttv *btv, |
241 | struct bttv_buffer_set *set); | 240 | struct bttv_buffer_set *set); |
242 | int bttv_buffer_activate_vbi(struct bttv *btv, | 241 | int bttv_buffer_activate_vbi(struct bttv *btv, |
243 | struct bttv_buffer *vbi); | 242 | struct bttv_buffer *vbi); |
244 | void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, | 243 | void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, |
245 | struct bttv_buffer *buf); | 244 | struct bttv_buffer *buf); |
246 | 245 | ||
247 | /* overlay handling */ | 246 | /* overlay handling */ |
248 | int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, | 247 | int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, |
249 | const struct bttv_format *fmt, | 248 | const struct bttv_format *fmt, |
250 | struct bttv_buffer *buf); | 249 | struct bttv_buffer *buf); |
251 | 250 | ||
252 | 251 | ||
253 | /* ---------------------------------------------------------- */ | 252 | /* ---------------------------------------------------------- */ |
254 | /* bttv-vbi.c */ | 253 | /* bttv-vbi.c */ |
255 | 254 | ||
256 | int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); | 255 | int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); |
257 | int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); | 256 | int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); |
258 | int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); | 257 | int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); |
259 | 258 | ||
260 | extern struct videobuf_queue_ops bttv_vbi_qops; | 259 | extern struct videobuf_queue_ops bttv_vbi_qops; |
261 | 260 | ||
262 | /* ---------------------------------------------------------- */ | 261 | /* ---------------------------------------------------------- */ |
263 | /* bttv-gpio.c */ | 262 | /* bttv-gpio.c */ |
264 | 263 | ||
265 | extern struct bus_type bttv_sub_bus_type; | 264 | extern struct bus_type bttv_sub_bus_type; |
266 | int bttv_sub_add_device(struct bttv_core *core, char *name); | 265 | int bttv_sub_add_device(struct bttv_core *core, char *name); |
267 | int bttv_sub_del_devices(struct bttv_core *core); | 266 | int bttv_sub_del_devices(struct bttv_core *core); |
268 | 267 | ||
269 | /* ---------------------------------------------------------- */ | 268 | /* ---------------------------------------------------------- */ |
270 | /* bttv-cards.c */ | 269 | /* bttv-cards.c */ |
271 | 270 | ||
272 | extern int no_overlay; | 271 | extern int no_overlay; |
273 | 272 | ||
274 | /* ---------------------------------------------------------- */ | 273 | /* ---------------------------------------------------------- */ |
275 | /* bttv-driver.c */ | 274 | /* bttv-driver.c */ |
276 | 275 | ||
277 | /* insmod options */ | 276 | /* insmod options */ |
278 | extern unsigned int bttv_verbose; | 277 | extern unsigned int bttv_verbose; |
279 | extern unsigned int bttv_debug; | 278 | extern unsigned int bttv_debug; |
280 | extern unsigned int bttv_gpio; | 279 | extern unsigned int bttv_gpio; |
281 | extern void bttv_gpio_tracking(struct bttv *btv, char *comment); | 280 | extern void bttv_gpio_tracking(struct bttv *btv, char *comment); |
282 | extern int init_bttv_i2c(struct bttv *btv); | 281 | extern int init_bttv_i2c(struct bttv *btv); |
283 | extern int fini_bttv_i2c(struct bttv *btv); | 282 | extern int fini_bttv_i2c(struct bttv *btv); |
284 | 283 | ||
285 | #define bttv_printk if (bttv_verbose) printk | 284 | #define bttv_printk if (bttv_verbose) printk |
286 | #define dprintk if (bttv_debug >= 1) printk | 285 | #define dprintk if (bttv_debug >= 1) printk |
287 | #define d2printk if (bttv_debug >= 2) printk | 286 | #define d2printk if (bttv_debug >= 2) printk |
288 | 287 | ||
289 | #define BTTV_MAX_FBUF 0x208000 | 288 | #define BTTV_MAX_FBUF 0x208000 |
290 | #define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | 289 | #define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ |
291 | #define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ | 290 | #define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ |
292 | 291 | ||
293 | 292 | ||
294 | struct bttv_pll_info { | 293 | struct bttv_pll_info { |
295 | unsigned int pll_ifreq; /* PLL input frequency */ | 294 | unsigned int pll_ifreq; /* PLL input frequency */ |
296 | unsigned int pll_ofreq; /* PLL output frequency */ | 295 | unsigned int pll_ofreq; /* PLL output frequency */ |
297 | unsigned int pll_crystal; /* Crystal used for input */ | 296 | unsigned int pll_crystal; /* Crystal used for input */ |
298 | unsigned int pll_current; /* Currently programmed ofreq */ | 297 | unsigned int pll_current; /* Currently programmed ofreq */ |
299 | }; | 298 | }; |
300 | 299 | ||
301 | /* for gpio-connected remote control */ | 300 | /* for gpio-connected remote control */ |
302 | struct bttv_input { | 301 | struct bttv_input { |
303 | struct input_dev *dev; | 302 | struct input_dev *dev; |
304 | struct ir_input_state ir; | 303 | struct ir_input_state ir; |
305 | char name[32]; | 304 | char name[32]; |
306 | char phys[32]; | 305 | char phys[32]; |
307 | u32 mask_keycode; | 306 | u32 mask_keycode; |
308 | u32 mask_keydown; | 307 | u32 mask_keydown; |
309 | }; | 308 | }; |
310 | 309 | ||
311 | struct bttv_suspend_state { | 310 | struct bttv_suspend_state { |
312 | u32 gpio_enable; | 311 | u32 gpio_enable; |
313 | u32 gpio_data; | 312 | u32 gpio_data; |
314 | int disabled; | 313 | int disabled; |
315 | int loop_irq; | 314 | int loop_irq; |
316 | struct bttv_buffer_set video; | 315 | struct bttv_buffer_set video; |
317 | struct bttv_buffer *vbi; | 316 | struct bttv_buffer *vbi; |
318 | }; | 317 | }; |
319 | 318 | ||
320 | struct bttv { | 319 | struct bttv { |
321 | struct bttv_core c; | 320 | struct bttv_core c; |
322 | 321 | ||
323 | /* pci device config */ | 322 | /* pci device config */ |
324 | unsigned short id; | 323 | unsigned short id; |
325 | unsigned char revision; | 324 | unsigned char revision; |
326 | unsigned char __iomem *bt848_mmio; /* pointer to mmio */ | 325 | unsigned char __iomem *bt848_mmio; /* pointer to mmio */ |
327 | 326 | ||
328 | /* card configuration info */ | 327 | /* card configuration info */ |
329 | unsigned int cardid; /* pci subsystem id (bt878 based ones) */ | 328 | unsigned int cardid; /* pci subsystem id (bt878 based ones) */ |
330 | unsigned int tuner_type; /* tuner chip type */ | 329 | unsigned int tuner_type; /* tuner chip type */ |
331 | unsigned int tda9887_conf; | 330 | unsigned int tda9887_conf; |
332 | unsigned int svhs, dig; | 331 | unsigned int svhs, dig; |
333 | struct bttv_pll_info pll; | 332 | struct bttv_pll_info pll; |
334 | int triton1; | 333 | int triton1; |
335 | int gpioirq; | 334 | int gpioirq; |
336 | int (*custom_irq)(struct bttv *btv); | 335 | int (*custom_irq)(struct bttv *btv); |
337 | 336 | ||
338 | int use_i2c_hw; | 337 | int use_i2c_hw; |
339 | 338 | ||
340 | /* old gpio interface */ | 339 | /* old gpio interface */ |
341 | wait_queue_head_t gpioq; | 340 | wait_queue_head_t gpioq; |
342 | int shutdown; | 341 | int shutdown; |
343 | 342 | ||
344 | void (*volume_gpio)(struct bttv *btv, __u16 volume); | 343 | void (*volume_gpio)(struct bttv *btv, __u16 volume); |
345 | void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); | 344 | void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); |
346 | 345 | ||
347 | /* new gpio interface */ | 346 | /* new gpio interface */ |
348 | spinlock_t gpio_lock; | 347 | spinlock_t gpio_lock; |
349 | 348 | ||
350 | /* i2c layer */ | 349 | /* i2c layer */ |
351 | struct i2c_algo_bit_data i2c_algo; | 350 | struct i2c_algo_bit_data i2c_algo; |
352 | struct i2c_client i2c_client; | 351 | struct i2c_client i2c_client; |
353 | int i2c_state, i2c_rc; | 352 | int i2c_state, i2c_rc; |
354 | int i2c_done; | 353 | int i2c_done; |
355 | wait_queue_head_t i2c_queue; | 354 | wait_queue_head_t i2c_queue; |
356 | struct i2c_client *i2c_msp34xx_client; | 355 | struct i2c_client *i2c_msp34xx_client; |
357 | struct i2c_client *i2c_tvaudio_client; | 356 | struct i2c_client *i2c_tvaudio_client; |
358 | 357 | ||
359 | /* video4linux (1) */ | 358 | /* video4linux (1) */ |
360 | struct video_device *video_dev; | 359 | struct video_device *video_dev; |
361 | struct video_device *radio_dev; | 360 | struct video_device *radio_dev; |
362 | struct video_device *vbi_dev; | 361 | struct video_device *vbi_dev; |
363 | 362 | ||
364 | /* infrared remote */ | 363 | /* infrared remote */ |
365 | int has_remote; | 364 | int has_remote; |
366 | struct card_ir *remote; | 365 | struct card_ir *remote; |
367 | 366 | ||
368 | /* locking */ | 367 | /* locking */ |
369 | spinlock_t s_lock; | 368 | spinlock_t s_lock; |
370 | struct mutex lock; | 369 | struct mutex lock; |
371 | int resources; | 370 | int resources; |
372 | #ifdef VIDIOC_G_PRIORITY | 371 | #ifdef VIDIOC_G_PRIORITY |
373 | struct v4l2_prio_state prio; | 372 | struct v4l2_prio_state prio; |
374 | #endif | 373 | #endif |
375 | 374 | ||
376 | /* video state */ | 375 | /* video state */ |
377 | unsigned int input; | 376 | unsigned int input; |
378 | unsigned int audio; | 377 | unsigned int audio; |
379 | unsigned int mute; | 378 | unsigned int mute; |
380 | unsigned long freq; | 379 | unsigned long freq; |
381 | unsigned int tvnorm; | 380 | unsigned int tvnorm; |
382 | int hue, contrast, bright, saturation; | 381 | int hue, contrast, bright, saturation; |
383 | struct v4l2_framebuffer fbuf; | 382 | struct v4l2_framebuffer fbuf; |
384 | unsigned int field_count; | 383 | unsigned int field_count; |
385 | 384 | ||
386 | /* various options */ | 385 | /* various options */ |
387 | int opt_combfilter; | 386 | int opt_combfilter; |
388 | int opt_lumafilter; | 387 | int opt_lumafilter; |
389 | int opt_automute; | 388 | int opt_automute; |
390 | int opt_chroma_agc; | 389 | int opt_chroma_agc; |
391 | int opt_adc_crush; | 390 | int opt_adc_crush; |
392 | int opt_vcr_hack; | 391 | int opt_vcr_hack; |
393 | int opt_whitecrush_upper; | 392 | int opt_whitecrush_upper; |
394 | int opt_whitecrush_lower; | 393 | int opt_whitecrush_lower; |
395 | int opt_uv_ratio; | 394 | int opt_uv_ratio; |
396 | int opt_full_luma_range; | 395 | int opt_full_luma_range; |
397 | int opt_coring; | 396 | int opt_coring; |
398 | 397 | ||
399 | /* radio data/state */ | 398 | /* radio data/state */ |
400 | int has_radio; | 399 | int has_radio; |
401 | int radio_user; | 400 | int radio_user; |
402 | 401 | ||
403 | /* miro/pinnacle + Aimslab VHX | 402 | /* miro/pinnacle + Aimslab VHX |
404 | philips matchbox (tea5757 radio tuner) support */ | 403 | philips matchbox (tea5757 radio tuner) support */ |
405 | int has_matchbox; | 404 | int has_matchbox; |
406 | int mbox_we; | 405 | int mbox_we; |
407 | int mbox_data; | 406 | int mbox_data; |
408 | int mbox_clk; | 407 | int mbox_clk; |
409 | int mbox_most; | 408 | int mbox_most; |
410 | int mbox_mask; | 409 | int mbox_mask; |
411 | 410 | ||
412 | /* ISA stuff (Terratec Active Radio Upgrade) */ | 411 | /* ISA stuff (Terratec Active Radio Upgrade) */ |
413 | int mbox_ior; | 412 | int mbox_ior; |
414 | int mbox_iow; | 413 | int mbox_iow; |
415 | int mbox_csel; | 414 | int mbox_csel; |
416 | 415 | ||
417 | /* risc memory management data | 416 | /* risc memory management data |
418 | - must acquire s_lock before changing these | 417 | - must acquire s_lock before changing these |
419 | - only the irq handler is supported to touch top + bottom + vcurr */ | 418 | - only the irq handler is supported to touch top + bottom + vcurr */ |
420 | struct btcx_riscmem main; | 419 | struct btcx_riscmem main; |
421 | struct bttv_buffer *screen; /* overlay */ | 420 | struct bttv_buffer *screen; /* overlay */ |
422 | struct list_head capture; /* video capture queue */ | 421 | struct list_head capture; /* video capture queue */ |
423 | struct list_head vcapture; /* vbi capture queue */ | 422 | struct list_head vcapture; /* vbi capture queue */ |
424 | struct bttv_buffer_set curr; /* active buffers */ | 423 | struct bttv_buffer_set curr; /* active buffers */ |
425 | struct bttv_buffer *cvbi; /* active vbi buffer */ | 424 | struct bttv_buffer *cvbi; /* active vbi buffer */ |
426 | int loop_irq; | 425 | int loop_irq; |
427 | int new_input; | 426 | int new_input; |
428 | 427 | ||
429 | unsigned long cap_ctl; | 428 | unsigned long cap_ctl; |
430 | unsigned long dma_on; | 429 | unsigned long dma_on; |
431 | struct timer_list timeout; | 430 | struct timer_list timeout; |
432 | struct bttv_suspend_state state; | 431 | struct bttv_suspend_state state; |
433 | 432 | ||
434 | /* stats */ | 433 | /* stats */ |
435 | unsigned int errors; | 434 | unsigned int errors; |
436 | unsigned int framedrop; | 435 | unsigned int framedrop; |
437 | unsigned int irq_total; | 436 | unsigned int irq_total; |
438 | unsigned int irq_me; | 437 | unsigned int irq_me; |
439 | 438 | ||
440 | unsigned int users; | 439 | unsigned int users; |
441 | struct bttv_fh init; | 440 | struct bttv_fh init; |
442 | 441 | ||
443 | /* used to make dvb-bt8xx autoloadable */ | 442 | /* used to make dvb-bt8xx autoloadable */ |
444 | struct work_struct request_module_wk; | 443 | struct work_struct request_module_wk; |
445 | 444 | ||
446 | /* Default (0) and current (1) video capturing and overlay | 445 | /* Default (0) and current (1) video capturing and overlay |
447 | cropping parameters in bttv_tvnorm.cropcap units. Protected | 446 | cropping parameters in bttv_tvnorm.cropcap units. Protected |
448 | by bttv.lock. */ | 447 | by bttv.lock. */ |
449 | struct bttv_crop crop[2]; | 448 | struct bttv_crop crop[2]; |
450 | 449 | ||
451 | /* Earliest possible start of video capturing in | 450 | /* Earliest possible start of video capturing in |
452 | bttv_tvnorm.cropcap line units. Set by check_alloc_btres() | 451 | bttv_tvnorm.cropcap line units. Set by check_alloc_btres() |
453 | and free_btres(). Protected by bttv.lock. */ | 452 | and free_btres(). Protected by bttv.lock. */ |
454 | __s32 vbi_end; | 453 | __s32 vbi_end; |
455 | 454 | ||
456 | /* Latest possible end of VBI capturing (= crop[x].rect.top when | 455 | /* Latest possible end of VBI capturing (= crop[x].rect.top when |
457 | VIDEO_RESOURCES are locked). Set by check_alloc_btres() | 456 | VIDEO_RESOURCES are locked). Set by check_alloc_btres() |
458 | and free_btres(). Protected by bttv.lock. */ | 457 | and free_btres(). Protected by bttv.lock. */ |
459 | __s32 crop_start; | 458 | __s32 crop_start; |
460 | }; | 459 | }; |
461 | 460 | ||
462 | /* our devices */ | 461 | /* our devices */ |
463 | #define BTTV_MAX 32 | 462 | #define BTTV_MAX 32 |
464 | extern unsigned int bttv_num; | 463 | extern unsigned int bttv_num; |
465 | extern struct bttv *bttvs[BTTV_MAX]; | 464 | extern struct bttv *bttvs[BTTV_MAX]; |
466 | 465 | ||
467 | static inline unsigned int bttv_muxsel(const struct bttv *btv, | 466 | static inline unsigned int bttv_muxsel(const struct bttv *btv, |
468 | unsigned int input) | 467 | unsigned int input) |
469 | { | 468 | { |
470 | return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; | 469 | return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; |
471 | } | 470 | } |
472 | 471 | ||
473 | #endif | 472 | #endif |
474 | 473 | ||
475 | #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) | 474 | #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) |
476 | #define btread(adr) readl(btv->bt848_mmio+(adr)) | 475 | #define btread(adr) readl(btv->bt848_mmio+(adr)) |
477 | 476 | ||
478 | #define btand(dat,adr) btwrite((dat) & btread(adr), adr) | 477 | #define btand(dat,adr) btwrite((dat) & btread(adr), adr) |
479 | #define btor(dat,adr) btwrite((dat) | btread(adr), adr) | 478 | #define btor(dat,adr) btwrite((dat) | btread(adr), adr) |
480 | #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) | 479 | #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) |
481 | 480 | ||
482 | #endif /* _BTTVP_H_ */ | 481 | #endif /* _BTTVP_H_ */ |
483 | 482 | ||
484 | /* | 483 | /* |
485 | * Local variables: | 484 | * Local variables: |
486 | * c-basic-offset: 8 | 485 | * c-basic-offset: 8 |
487 | * End: | 486 | * End: |
488 | */ | 487 | */ |
489 | 488 |
drivers/media/video/cpia2/cpia2_v4l.c
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | * | 2 | * |
3 | * Filename: cpia2_v4l.c | 3 | * Filename: cpia2_v4l.c |
4 | * | 4 | * |
5 | * Copyright 2001, STMicrolectronics, Inc. | 5 | * Copyright 2001, STMicrolectronics, Inc. |
6 | * Contact: steve.miller@st.com | 6 | * Contact: steve.miller@st.com |
7 | * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> | 7 | * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> |
8 | * | 8 | * |
9 | * Description: | 9 | * Description: |
10 | * This is a USB driver for CPia2 based video cameras. | 10 | * This is a USB driver for CPia2 based video cameras. |
11 | * The infrastructure of this driver is based on the cpia usb driver by | 11 | * The infrastructure of this driver is based on the cpia usb driver by |
12 | * Jochen Scharrlach and Johannes Erdfeldt. | 12 | * Jochen Scharrlach and Johannes Erdfeldt. |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. | 17 | * (at your option) any later version. |
18 | * | 18 | * |
19 | * This program is distributed in the hope that it will be useful, | 19 | * This program is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
23 | * | 23 | * |
24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, write to the Free Software |
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | * | 27 | * |
28 | * Stripped of 2.4 stuff ready for main kernel submit by | 28 | * Stripped of 2.4 stuff ready for main kernel submit by |
29 | * Alan Cox <alan@lxorguk.ukuu.org.uk> | 29 | * Alan Cox <alan@lxorguk.ukuu.org.uk> |
30 | ****************************************************************************/ | 30 | ****************************************************************************/ |
31 | 31 | ||
32 | #include <linux/version.h> | 32 | #include <linux/version.h> |
33 | 33 | ||
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/time.h> | 36 | #include <linux/time.h> |
37 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
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 <media/v4l2-ioctl.h> | 41 | #include <media/v4l2-ioctl.h> |
41 | 42 | ||
42 | #include "cpia2.h" | 43 | #include "cpia2.h" |
43 | #include "cpia2dev.h" | 44 | #include "cpia2dev.h" |
44 | 45 | ||
45 | 46 | ||
46 | //#define _CPIA2_DEBUG_ | 47 | //#define _CPIA2_DEBUG_ |
47 | 48 | ||
48 | #define MAKE_STRING_1(x) #x | 49 | #define MAKE_STRING_1(x) #x |
49 | #define MAKE_STRING(x) MAKE_STRING_1(x) | 50 | #define MAKE_STRING(x) MAKE_STRING_1(x) |
50 | 51 | ||
51 | static int video_nr = -1; | 52 | static int video_nr = -1; |
52 | module_param(video_nr, int, 0); | 53 | module_param(video_nr, int, 0); |
53 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); | 54 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); |
54 | 55 | ||
55 | static int buffer_size = 68*1024; | 56 | static int buffer_size = 68*1024; |
56 | module_param(buffer_size, int, 0); | 57 | module_param(buffer_size, int, 0); |
57 | MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); | 58 | MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); |
58 | 59 | ||
59 | static int num_buffers = 3; | 60 | static int num_buffers = 3; |
60 | module_param(num_buffers, int, 0); | 61 | module_param(num_buffers, int, 0); |
61 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" | 62 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" |
62 | MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); | 63 | MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); |
63 | 64 | ||
64 | static int alternate = DEFAULT_ALT; | 65 | static int alternate = DEFAULT_ALT; |
65 | module_param(alternate, int, 0); | 66 | module_param(alternate, int, 0); |
66 | MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" | 67 | MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" |
67 | MAKE_STRING(USBIF_ISO_6) ", default " | 68 | MAKE_STRING(USBIF_ISO_6) ", default " |
68 | MAKE_STRING(DEFAULT_ALT) ")"); | 69 | MAKE_STRING(DEFAULT_ALT) ")"); |
69 | 70 | ||
70 | static int flicker_freq = 60; | 71 | static int flicker_freq = 60; |
71 | module_param(flicker_freq, int, 0); | 72 | module_param(flicker_freq, int, 0); |
72 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" | 73 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" |
73 | MAKE_STRING(60) ", default " | 74 | MAKE_STRING(60) ", default " |
74 | MAKE_STRING(60) ")"); | 75 | MAKE_STRING(60) ")"); |
75 | 76 | ||
76 | static int flicker_mode = NEVER_FLICKER; | 77 | static int flicker_mode = NEVER_FLICKER; |
77 | module_param(flicker_mode, int, 0); | 78 | module_param(flicker_mode, int, 0); |
78 | MODULE_PARM_DESC(flicker_mode, | 79 | MODULE_PARM_DESC(flicker_mode, |
79 | "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" | 80 | "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" |
80 | MAKE_STRING(ANTI_FLICKER_ON) ", default " | 81 | MAKE_STRING(ANTI_FLICKER_ON) ", default " |
81 | MAKE_STRING(NEVER_FLICKER) ")"); | 82 | MAKE_STRING(NEVER_FLICKER) ")"); |
82 | 83 | ||
83 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); | 84 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); |
84 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); | 85 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); |
85 | MODULE_SUPPORTED_DEVICE("video"); | 86 | MODULE_SUPPORTED_DEVICE("video"); |
86 | MODULE_LICENSE("GPL"); | 87 | MODULE_LICENSE("GPL"); |
87 | 88 | ||
88 | #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" | 89 | #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" |
89 | 90 | ||
90 | struct control_menu_info { | 91 | struct control_menu_info { |
91 | int value; | 92 | int value; |
92 | char name[32]; | 93 | char name[32]; |
93 | }; | 94 | }; |
94 | 95 | ||
95 | static struct control_menu_info framerate_controls[] = | 96 | static struct control_menu_info framerate_controls[] = |
96 | { | 97 | { |
97 | { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, | 98 | { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, |
98 | { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, | 99 | { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, |
99 | { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, | 100 | { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, |
100 | { CPIA2_VP_FRAMERATE_15, "15 fps" }, | 101 | { CPIA2_VP_FRAMERATE_15, "15 fps" }, |
101 | { CPIA2_VP_FRAMERATE_25, "25 fps" }, | 102 | { CPIA2_VP_FRAMERATE_25, "25 fps" }, |
102 | { CPIA2_VP_FRAMERATE_30, "30 fps" }, | 103 | { CPIA2_VP_FRAMERATE_30, "30 fps" }, |
103 | }; | 104 | }; |
104 | #define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) | 105 | #define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) |
105 | 106 | ||
106 | static struct control_menu_info flicker_controls[] = | 107 | static struct control_menu_info flicker_controls[] = |
107 | { | 108 | { |
108 | { NEVER_FLICKER, "Off" }, | 109 | { NEVER_FLICKER, "Off" }, |
109 | { FLICKER_50, "50 Hz" }, | 110 | { FLICKER_50, "50 Hz" }, |
110 | { FLICKER_60, "60 Hz" }, | 111 | { FLICKER_60, "60 Hz" }, |
111 | }; | 112 | }; |
112 | #define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) | 113 | #define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) |
113 | 114 | ||
114 | static struct control_menu_info lights_controls[] = | 115 | static struct control_menu_info lights_controls[] = |
115 | { | 116 | { |
116 | { 0, "Off" }, | 117 | { 0, "Off" }, |
117 | { 64, "Top" }, | 118 | { 64, "Top" }, |
118 | { 128, "Bottom" }, | 119 | { 128, "Bottom" }, |
119 | { 192, "Both" }, | 120 | { 192, "Both" }, |
120 | }; | 121 | }; |
121 | #define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) | 122 | #define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) |
122 | #define GPIO_LIGHTS_MASK 192 | 123 | #define GPIO_LIGHTS_MASK 192 |
123 | 124 | ||
124 | static struct v4l2_queryctrl controls[] = { | 125 | static struct v4l2_queryctrl controls[] = { |
125 | { | 126 | { |
126 | .id = V4L2_CID_BRIGHTNESS, | 127 | .id = V4L2_CID_BRIGHTNESS, |
127 | .type = V4L2_CTRL_TYPE_INTEGER, | 128 | .type = V4L2_CTRL_TYPE_INTEGER, |
128 | .name = "Brightness", | 129 | .name = "Brightness", |
129 | .minimum = 0, | 130 | .minimum = 0, |
130 | .maximum = 255, | 131 | .maximum = 255, |
131 | .step = 1, | 132 | .step = 1, |
132 | .default_value = DEFAULT_BRIGHTNESS, | 133 | .default_value = DEFAULT_BRIGHTNESS, |
133 | }, | 134 | }, |
134 | { | 135 | { |
135 | .id = V4L2_CID_CONTRAST, | 136 | .id = V4L2_CID_CONTRAST, |
136 | .type = V4L2_CTRL_TYPE_INTEGER, | 137 | .type = V4L2_CTRL_TYPE_INTEGER, |
137 | .name = "Contrast", | 138 | .name = "Contrast", |
138 | .minimum = 0, | 139 | .minimum = 0, |
139 | .maximum = 255, | 140 | .maximum = 255, |
140 | .step = 1, | 141 | .step = 1, |
141 | .default_value = DEFAULT_CONTRAST, | 142 | .default_value = DEFAULT_CONTRAST, |
142 | }, | 143 | }, |
143 | { | 144 | { |
144 | .id = V4L2_CID_SATURATION, | 145 | .id = V4L2_CID_SATURATION, |
145 | .type = V4L2_CTRL_TYPE_INTEGER, | 146 | .type = V4L2_CTRL_TYPE_INTEGER, |
146 | .name = "Saturation", | 147 | .name = "Saturation", |
147 | .minimum = 0, | 148 | .minimum = 0, |
148 | .maximum = 255, | 149 | .maximum = 255, |
149 | .step = 1, | 150 | .step = 1, |
150 | .default_value = DEFAULT_SATURATION, | 151 | .default_value = DEFAULT_SATURATION, |
151 | }, | 152 | }, |
152 | { | 153 | { |
153 | .id = V4L2_CID_HFLIP, | 154 | .id = V4L2_CID_HFLIP, |
154 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 155 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
155 | .name = "Mirror Horizontally", | 156 | .name = "Mirror Horizontally", |
156 | .minimum = 0, | 157 | .minimum = 0, |
157 | .maximum = 1, | 158 | .maximum = 1, |
158 | .step = 1, | 159 | .step = 1, |
159 | .default_value = 0, | 160 | .default_value = 0, |
160 | }, | 161 | }, |
161 | { | 162 | { |
162 | .id = V4L2_CID_VFLIP, | 163 | .id = V4L2_CID_VFLIP, |
163 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 164 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
164 | .name = "Flip Vertically", | 165 | .name = "Flip Vertically", |
165 | .minimum = 0, | 166 | .minimum = 0, |
166 | .maximum = 1, | 167 | .maximum = 1, |
167 | .step = 1, | 168 | .step = 1, |
168 | .default_value = 0, | 169 | .default_value = 0, |
169 | }, | 170 | }, |
170 | { | 171 | { |
171 | .id = CPIA2_CID_TARGET_KB, | 172 | .id = CPIA2_CID_TARGET_KB, |
172 | .type = V4L2_CTRL_TYPE_INTEGER, | 173 | .type = V4L2_CTRL_TYPE_INTEGER, |
173 | .name = "Target KB", | 174 | .name = "Target KB", |
174 | .minimum = 0, | 175 | .minimum = 0, |
175 | .maximum = 255, | 176 | .maximum = 255, |
176 | .step = 1, | 177 | .step = 1, |
177 | .default_value = DEFAULT_TARGET_KB, | 178 | .default_value = DEFAULT_TARGET_KB, |
178 | }, | 179 | }, |
179 | { | 180 | { |
180 | .id = CPIA2_CID_GPIO, | 181 | .id = CPIA2_CID_GPIO, |
181 | .type = V4L2_CTRL_TYPE_INTEGER, | 182 | .type = V4L2_CTRL_TYPE_INTEGER, |
182 | .name = "GPIO", | 183 | .name = "GPIO", |
183 | .minimum = 0, | 184 | .minimum = 0, |
184 | .maximum = 255, | 185 | .maximum = 255, |
185 | .step = 1, | 186 | .step = 1, |
186 | .default_value = 0, | 187 | .default_value = 0, |
187 | }, | 188 | }, |
188 | { | 189 | { |
189 | .id = CPIA2_CID_FLICKER_MODE, | 190 | .id = CPIA2_CID_FLICKER_MODE, |
190 | .type = V4L2_CTRL_TYPE_MENU, | 191 | .type = V4L2_CTRL_TYPE_MENU, |
191 | .name = "Flicker Reduction", | 192 | .name = "Flicker Reduction", |
192 | .minimum = 0, | 193 | .minimum = 0, |
193 | .maximum = NUM_FLICKER_CONTROLS-1, | 194 | .maximum = NUM_FLICKER_CONTROLS-1, |
194 | .step = 1, | 195 | .step = 1, |
195 | .default_value = 0, | 196 | .default_value = 0, |
196 | }, | 197 | }, |
197 | { | 198 | { |
198 | .id = CPIA2_CID_FRAMERATE, | 199 | .id = CPIA2_CID_FRAMERATE, |
199 | .type = V4L2_CTRL_TYPE_MENU, | 200 | .type = V4L2_CTRL_TYPE_MENU, |
200 | .name = "Framerate", | 201 | .name = "Framerate", |
201 | .minimum = 0, | 202 | .minimum = 0, |
202 | .maximum = NUM_FRAMERATE_CONTROLS-1, | 203 | .maximum = NUM_FRAMERATE_CONTROLS-1, |
203 | .step = 1, | 204 | .step = 1, |
204 | .default_value = NUM_FRAMERATE_CONTROLS-1, | 205 | .default_value = NUM_FRAMERATE_CONTROLS-1, |
205 | }, | 206 | }, |
206 | { | 207 | { |
207 | .id = CPIA2_CID_USB_ALT, | 208 | .id = CPIA2_CID_USB_ALT, |
208 | .type = V4L2_CTRL_TYPE_INTEGER, | 209 | .type = V4L2_CTRL_TYPE_INTEGER, |
209 | .name = "USB Alternate", | 210 | .name = "USB Alternate", |
210 | .minimum = USBIF_ISO_1, | 211 | .minimum = USBIF_ISO_1, |
211 | .maximum = USBIF_ISO_6, | 212 | .maximum = USBIF_ISO_6, |
212 | .step = 1, | 213 | .step = 1, |
213 | .default_value = DEFAULT_ALT, | 214 | .default_value = DEFAULT_ALT, |
214 | }, | 215 | }, |
215 | { | 216 | { |
216 | .id = CPIA2_CID_LIGHTS, | 217 | .id = CPIA2_CID_LIGHTS, |
217 | .type = V4L2_CTRL_TYPE_MENU, | 218 | .type = V4L2_CTRL_TYPE_MENU, |
218 | .name = "Lights", | 219 | .name = "Lights", |
219 | .minimum = 0, | 220 | .minimum = 0, |
220 | .maximum = NUM_LIGHTS_CONTROLS-1, | 221 | .maximum = NUM_LIGHTS_CONTROLS-1, |
221 | .step = 1, | 222 | .step = 1, |
222 | .default_value = 0, | 223 | .default_value = 0, |
223 | }, | 224 | }, |
224 | { | 225 | { |
225 | .id = CPIA2_CID_RESET_CAMERA, | 226 | .id = CPIA2_CID_RESET_CAMERA, |
226 | .type = V4L2_CTRL_TYPE_BUTTON, | 227 | .type = V4L2_CTRL_TYPE_BUTTON, |
227 | .name = "Reset Camera", | 228 | .name = "Reset Camera", |
228 | .minimum = 0, | 229 | .minimum = 0, |
229 | .maximum = 0, | 230 | .maximum = 0, |
230 | .step = 0, | 231 | .step = 0, |
231 | .default_value = 0, | 232 | .default_value = 0, |
232 | }, | 233 | }, |
233 | }; | 234 | }; |
234 | #define NUM_CONTROLS (ARRAY_SIZE(controls)) | 235 | #define NUM_CONTROLS (ARRAY_SIZE(controls)) |
235 | 236 | ||
236 | 237 | ||
237 | /****************************************************************************** | 238 | /****************************************************************************** |
238 | * | 239 | * |
239 | * cpia2_open | 240 | * cpia2_open |
240 | * | 241 | * |
241 | *****************************************************************************/ | 242 | *****************************************************************************/ |
242 | static int cpia2_open(struct file *file) | 243 | static int cpia2_open(struct file *file) |
243 | { | 244 | { |
244 | struct camera_data *cam = video_drvdata(file); | 245 | struct camera_data *cam = video_drvdata(file); |
245 | int retval = 0; | 246 | int retval = 0; |
246 | 247 | ||
247 | if (!cam) { | 248 | if (!cam) { |
248 | ERR("Internal error, camera_data not found!\n"); | 249 | ERR("Internal error, camera_data not found!\n"); |
249 | return -ENODEV; | 250 | return -ENODEV; |
250 | } | 251 | } |
251 | 252 | ||
252 | if(mutex_lock_interruptible(&cam->busy_lock)) | 253 | if(mutex_lock_interruptible(&cam->busy_lock)) |
253 | return -ERESTARTSYS; | 254 | return -ERESTARTSYS; |
254 | 255 | ||
255 | if(!cam->present) { | 256 | if(!cam->present) { |
256 | retval = -ENODEV; | 257 | retval = -ENODEV; |
257 | goto err_return; | 258 | goto err_return; |
258 | } | 259 | } |
259 | 260 | ||
260 | if (cam->open_count > 0) { | 261 | if (cam->open_count > 0) { |
261 | goto skip_init; | 262 | goto skip_init; |
262 | } | 263 | } |
263 | 264 | ||
264 | if (cpia2_allocate_buffers(cam)) { | 265 | if (cpia2_allocate_buffers(cam)) { |
265 | retval = -ENOMEM; | 266 | retval = -ENOMEM; |
266 | goto err_return; | 267 | goto err_return; |
267 | } | 268 | } |
268 | 269 | ||
269 | /* reset the camera */ | 270 | /* reset the camera */ |
270 | if (cpia2_reset_camera(cam) < 0) { | 271 | if (cpia2_reset_camera(cam) < 0) { |
271 | retval = -EIO; | 272 | retval = -EIO; |
272 | goto err_return; | 273 | goto err_return; |
273 | } | 274 | } |
274 | 275 | ||
275 | cam->APP_len = 0; | 276 | cam->APP_len = 0; |
276 | cam->COM_len = 0; | 277 | cam->COM_len = 0; |
277 | 278 | ||
278 | skip_init: | 279 | skip_init: |
279 | { | 280 | { |
280 | struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); | 281 | struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); |
281 | if(!fh) { | 282 | if(!fh) { |
282 | retval = -ENOMEM; | 283 | retval = -ENOMEM; |
283 | goto err_return; | 284 | goto err_return; |
284 | } | 285 | } |
285 | file->private_data = fh; | 286 | file->private_data = fh; |
286 | fh->prio = V4L2_PRIORITY_UNSET; | 287 | fh->prio = V4L2_PRIORITY_UNSET; |
287 | v4l2_prio_open(&cam->prio, &fh->prio); | 288 | v4l2_prio_open(&cam->prio, &fh->prio); |
288 | fh->mmapped = 0; | 289 | fh->mmapped = 0; |
289 | } | 290 | } |
290 | 291 | ||
291 | ++cam->open_count; | 292 | ++cam->open_count; |
292 | 293 | ||
293 | cpia2_dbg_dump_registers(cam); | 294 | cpia2_dbg_dump_registers(cam); |
294 | 295 | ||
295 | err_return: | 296 | err_return: |
296 | mutex_unlock(&cam->busy_lock); | 297 | mutex_unlock(&cam->busy_lock); |
297 | return retval; | 298 | return retval; |
298 | } | 299 | } |
299 | 300 | ||
300 | /****************************************************************************** | 301 | /****************************************************************************** |
301 | * | 302 | * |
302 | * cpia2_close | 303 | * cpia2_close |
303 | * | 304 | * |
304 | *****************************************************************************/ | 305 | *****************************************************************************/ |
305 | static int cpia2_close(struct file *file) | 306 | static int cpia2_close(struct file *file) |
306 | { | 307 | { |
307 | struct video_device *dev = video_devdata(file); | 308 | struct video_device *dev = video_devdata(file); |
308 | struct camera_data *cam = video_get_drvdata(dev); | 309 | struct camera_data *cam = video_get_drvdata(dev); |
309 | struct cpia2_fh *fh = file->private_data; | 310 | struct cpia2_fh *fh = file->private_data; |
310 | 311 | ||
311 | mutex_lock(&cam->busy_lock); | 312 | mutex_lock(&cam->busy_lock); |
312 | 313 | ||
313 | if (cam->present && | 314 | if (cam->present && |
314 | (cam->open_count == 1 | 315 | (cam->open_count == 1 |
315 | || fh->prio == V4L2_PRIORITY_RECORD | 316 | || fh->prio == V4L2_PRIORITY_RECORD |
316 | )) { | 317 | )) { |
317 | cpia2_usb_stream_stop(cam); | 318 | cpia2_usb_stream_stop(cam); |
318 | 319 | ||
319 | if(cam->open_count == 1) { | 320 | if(cam->open_count == 1) { |
320 | /* save camera state for later open */ | 321 | /* save camera state for later open */ |
321 | cpia2_save_camera_state(cam); | 322 | cpia2_save_camera_state(cam); |
322 | 323 | ||
323 | cpia2_set_low_power(cam); | 324 | cpia2_set_low_power(cam); |
324 | cpia2_free_buffers(cam); | 325 | cpia2_free_buffers(cam); |
325 | } | 326 | } |
326 | } | 327 | } |
327 | 328 | ||
328 | { | 329 | { |
329 | if(fh->mmapped) | 330 | if(fh->mmapped) |
330 | cam->mmapped = 0; | 331 | cam->mmapped = 0; |
331 | v4l2_prio_close(&cam->prio,&fh->prio); | 332 | v4l2_prio_close(&cam->prio,&fh->prio); |
332 | file->private_data = NULL; | 333 | file->private_data = NULL; |
333 | kfree(fh); | 334 | kfree(fh); |
334 | } | 335 | } |
335 | 336 | ||
336 | if (--cam->open_count == 0) { | 337 | if (--cam->open_count == 0) { |
337 | cpia2_free_buffers(cam); | 338 | cpia2_free_buffers(cam); |
338 | if (!cam->present) { | 339 | if (!cam->present) { |
339 | video_unregister_device(dev); | 340 | video_unregister_device(dev); |
340 | mutex_unlock(&cam->busy_lock); | 341 | mutex_unlock(&cam->busy_lock); |
341 | kfree(cam); | 342 | kfree(cam); |
342 | return 0; | 343 | return 0; |
343 | } | 344 | } |
344 | } | 345 | } |
345 | 346 | ||
346 | mutex_unlock(&cam->busy_lock); | 347 | mutex_unlock(&cam->busy_lock); |
347 | 348 | ||
348 | return 0; | 349 | return 0; |
349 | } | 350 | } |
350 | 351 | ||
351 | /****************************************************************************** | 352 | /****************************************************************************** |
352 | * | 353 | * |
353 | * cpia2_v4l_read | 354 | * cpia2_v4l_read |
354 | * | 355 | * |
355 | *****************************************************************************/ | 356 | *****************************************************************************/ |
356 | static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, | 357 | static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, |
357 | loff_t *off) | 358 | loff_t *off) |
358 | { | 359 | { |
359 | struct camera_data *cam = video_drvdata(file); | 360 | struct camera_data *cam = video_drvdata(file); |
360 | int noblock = file->f_flags&O_NONBLOCK; | 361 | int noblock = file->f_flags&O_NONBLOCK; |
361 | 362 | ||
362 | struct cpia2_fh *fh = file->private_data; | 363 | struct cpia2_fh *fh = file->private_data; |
363 | 364 | ||
364 | if(!cam) | 365 | if(!cam) |
365 | return -EINVAL; | 366 | return -EINVAL; |
366 | 367 | ||
367 | /* Priority check */ | 368 | /* Priority check */ |
368 | if(fh->prio != V4L2_PRIORITY_RECORD) { | 369 | if(fh->prio != V4L2_PRIORITY_RECORD) { |
369 | return -EBUSY; | 370 | return -EBUSY; |
370 | } | 371 | } |
371 | 372 | ||
372 | return cpia2_read(cam, buf, count, noblock); | 373 | return cpia2_read(cam, buf, count, noblock); |
373 | } | 374 | } |
374 | 375 | ||
375 | 376 | ||
376 | /****************************************************************************** | 377 | /****************************************************************************** |
377 | * | 378 | * |
378 | * cpia2_v4l_poll | 379 | * cpia2_v4l_poll |
379 | * | 380 | * |
380 | *****************************************************************************/ | 381 | *****************************************************************************/ |
381 | static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) | 382 | static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) |
382 | { | 383 | { |
383 | struct camera_data *cam = video_drvdata(filp); | 384 | struct camera_data *cam = video_drvdata(filp); |
384 | struct cpia2_fh *fh = filp->private_data; | 385 | struct cpia2_fh *fh = filp->private_data; |
385 | 386 | ||
386 | if(!cam) | 387 | if(!cam) |
387 | return POLLERR; | 388 | return POLLERR; |
388 | 389 | ||
389 | /* Priority check */ | 390 | /* Priority check */ |
390 | if(fh->prio != V4L2_PRIORITY_RECORD) { | 391 | if(fh->prio != V4L2_PRIORITY_RECORD) { |
391 | return POLLERR; | 392 | return POLLERR; |
392 | } | 393 | } |
393 | 394 | ||
394 | return cpia2_poll(cam, filp, wait); | 395 | return cpia2_poll(cam, filp, wait); |
395 | } | 396 | } |
396 | 397 | ||
397 | 398 | ||
398 | /****************************************************************************** | 399 | /****************************************************************************** |
399 | * | 400 | * |
400 | * ioctl_cap_query | 401 | * ioctl_cap_query |
401 | * | 402 | * |
402 | *****************************************************************************/ | 403 | *****************************************************************************/ |
403 | static int ioctl_cap_query(void *arg, struct camera_data *cam) | 404 | static int ioctl_cap_query(void *arg, struct camera_data *cam) |
404 | { | 405 | { |
405 | struct video_capability *vc; | 406 | struct video_capability *vc; |
406 | int retval = 0; | 407 | int retval = 0; |
407 | vc = arg; | 408 | vc = arg; |
408 | 409 | ||
409 | if (cam->params.pnp_id.product == 0x151) | 410 | if (cam->params.pnp_id.product == 0x151) |
410 | strcpy(vc->name, "QX5 Microscope"); | 411 | strcpy(vc->name, "QX5 Microscope"); |
411 | else | 412 | else |
412 | strcpy(vc->name, "CPiA2 Camera"); | 413 | strcpy(vc->name, "CPiA2 Camera"); |
413 | 414 | ||
414 | vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER; | 415 | vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER; |
415 | vc->channels = 1; | 416 | vc->channels = 1; |
416 | vc->audios = 0; | 417 | vc->audios = 0; |
417 | vc->minwidth = 176; /* VIDEOSIZE_QCIF */ | 418 | vc->minwidth = 176; /* VIDEOSIZE_QCIF */ |
418 | vc->minheight = 144; | 419 | vc->minheight = 144; |
419 | switch (cam->params.version.sensor_flags) { | 420 | switch (cam->params.version.sensor_flags) { |
420 | case CPIA2_VP_SENSOR_FLAGS_500: | 421 | case CPIA2_VP_SENSOR_FLAGS_500: |
421 | vc->maxwidth = STV_IMAGE_VGA_COLS; | 422 | vc->maxwidth = STV_IMAGE_VGA_COLS; |
422 | vc->maxheight = STV_IMAGE_VGA_ROWS; | 423 | vc->maxheight = STV_IMAGE_VGA_ROWS; |
423 | break; | 424 | break; |
424 | case CPIA2_VP_SENSOR_FLAGS_410: | 425 | case CPIA2_VP_SENSOR_FLAGS_410: |
425 | vc->maxwidth = STV_IMAGE_CIF_COLS; | 426 | vc->maxwidth = STV_IMAGE_CIF_COLS; |
426 | vc->maxheight = STV_IMAGE_CIF_ROWS; | 427 | vc->maxheight = STV_IMAGE_CIF_ROWS; |
427 | break; | 428 | break; |
428 | default: | 429 | default: |
429 | return -EINVAL; | 430 | return -EINVAL; |
430 | } | 431 | } |
431 | 432 | ||
432 | return retval; | 433 | return retval; |
433 | } | 434 | } |
434 | 435 | ||
435 | /****************************************************************************** | 436 | /****************************************************************************** |
436 | * | 437 | * |
437 | * ioctl_get_channel | 438 | * ioctl_get_channel |
438 | * | 439 | * |
439 | *****************************************************************************/ | 440 | *****************************************************************************/ |
440 | static int ioctl_get_channel(void *arg) | 441 | static int ioctl_get_channel(void *arg) |
441 | { | 442 | { |
442 | int retval = 0; | 443 | int retval = 0; |
443 | struct video_channel *v; | 444 | struct video_channel *v; |
444 | v = arg; | 445 | v = arg; |
445 | 446 | ||
446 | if (v->channel != 0) | 447 | if (v->channel != 0) |
447 | return -EINVAL; | 448 | return -EINVAL; |
448 | 449 | ||
449 | v->channel = 0; | 450 | v->channel = 0; |
450 | strcpy(v->name, "Camera"); | 451 | strcpy(v->name, "Camera"); |
451 | v->tuners = 0; | 452 | v->tuners = 0; |
452 | v->flags = 0; | 453 | v->flags = 0; |
453 | v->type = VIDEO_TYPE_CAMERA; | 454 | v->type = VIDEO_TYPE_CAMERA; |
454 | v->norm = 0; | 455 | v->norm = 0; |
455 | 456 | ||
456 | return retval; | 457 | return retval; |
457 | } | 458 | } |
458 | 459 | ||
459 | /****************************************************************************** | 460 | /****************************************************************************** |
460 | * | 461 | * |
461 | * ioctl_set_channel | 462 | * ioctl_set_channel |
462 | * | 463 | * |
463 | *****************************************************************************/ | 464 | *****************************************************************************/ |
464 | static int ioctl_set_channel(void *arg) | 465 | static int ioctl_set_channel(void *arg) |
465 | { | 466 | { |
466 | struct video_channel *v; | 467 | struct video_channel *v; |
467 | int retval = 0; | 468 | int retval = 0; |
468 | v = arg; | 469 | v = arg; |
469 | 470 | ||
470 | if (retval == 0 && v->channel != 0) | 471 | if (retval == 0 && v->channel != 0) |
471 | retval = -EINVAL; | 472 | retval = -EINVAL; |
472 | 473 | ||
473 | return retval; | 474 | return retval; |
474 | } | 475 | } |
475 | 476 | ||
476 | /****************************************************************************** | 477 | /****************************************************************************** |
477 | * | 478 | * |
478 | * ioctl_set_image_prop | 479 | * ioctl_set_image_prop |
479 | * | 480 | * |
480 | *****************************************************************************/ | 481 | *****************************************************************************/ |
481 | static int ioctl_set_image_prop(void *arg, struct camera_data *cam) | 482 | static int ioctl_set_image_prop(void *arg, struct camera_data *cam) |
482 | { | 483 | { |
483 | struct video_picture *vp; | 484 | struct video_picture *vp; |
484 | int retval = 0; | 485 | int retval = 0; |
485 | vp = arg; | 486 | vp = arg; |
486 | 487 | ||
487 | /* brightness, color, contrast need no check 0-65535 */ | 488 | /* brightness, color, contrast need no check 0-65535 */ |
488 | memcpy(&cam->vp, vp, sizeof(*vp)); | 489 | memcpy(&cam->vp, vp, sizeof(*vp)); |
489 | 490 | ||
490 | /* update cam->params.colorParams */ | 491 | /* update cam->params.colorParams */ |
491 | cam->params.color_params.brightness = vp->brightness / 256; | 492 | cam->params.color_params.brightness = vp->brightness / 256; |
492 | cam->params.color_params.saturation = vp->colour / 256; | 493 | cam->params.color_params.saturation = vp->colour / 256; |
493 | cam->params.color_params.contrast = vp->contrast / 256; | 494 | cam->params.color_params.contrast = vp->contrast / 256; |
494 | 495 | ||
495 | DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n", | 496 | DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n", |
496 | cam->params.color_params.brightness, | 497 | cam->params.color_params.brightness, |
497 | cam->params.color_params.saturation, | 498 | cam->params.color_params.saturation, |
498 | cam->params.color_params.contrast); | 499 | cam->params.color_params.contrast); |
499 | 500 | ||
500 | cpia2_set_color_params(cam); | 501 | cpia2_set_color_params(cam); |
501 | 502 | ||
502 | return retval; | 503 | return retval; |
503 | } | 504 | } |
504 | 505 | ||
505 | static int sync(struct camera_data *cam, int frame_nr) | 506 | static int sync(struct camera_data *cam, int frame_nr) |
506 | { | 507 | { |
507 | struct framebuf *frame = &cam->buffers[frame_nr]; | 508 | struct framebuf *frame = &cam->buffers[frame_nr]; |
508 | 509 | ||
509 | while (1) { | 510 | while (1) { |
510 | if (frame->status == FRAME_READY) | 511 | if (frame->status == FRAME_READY) |
511 | return 0; | 512 | return 0; |
512 | 513 | ||
513 | if (!cam->streaming) { | 514 | if (!cam->streaming) { |
514 | frame->status = FRAME_READY; | 515 | frame->status = FRAME_READY; |
515 | frame->length = 0; | 516 | frame->length = 0; |
516 | return 0; | 517 | return 0; |
517 | } | 518 | } |
518 | 519 | ||
519 | mutex_unlock(&cam->busy_lock); | 520 | mutex_unlock(&cam->busy_lock); |
520 | wait_event_interruptible(cam->wq_stream, | 521 | wait_event_interruptible(cam->wq_stream, |
521 | !cam->streaming || | 522 | !cam->streaming || |
522 | frame->status == FRAME_READY); | 523 | frame->status == FRAME_READY); |
523 | mutex_lock(&cam->busy_lock); | 524 | mutex_lock(&cam->busy_lock); |
524 | if (signal_pending(current)) | 525 | if (signal_pending(current)) |
525 | return -ERESTARTSYS; | 526 | return -ERESTARTSYS; |
526 | if(!cam->present) | 527 | if(!cam->present) |
527 | return -ENOTTY; | 528 | return -ENOTTY; |
528 | } | 529 | } |
529 | } | 530 | } |
530 | 531 | ||
531 | /****************************************************************************** | 532 | /****************************************************************************** |
532 | * | 533 | * |
533 | * ioctl_set_window_size | 534 | * ioctl_set_window_size |
534 | * | 535 | * |
535 | *****************************************************************************/ | 536 | *****************************************************************************/ |
536 | static int ioctl_set_window_size(void *arg, struct camera_data *cam, | 537 | static int ioctl_set_window_size(void *arg, struct camera_data *cam, |
537 | struct cpia2_fh *fh) | 538 | struct cpia2_fh *fh) |
538 | { | 539 | { |
539 | /* copy_from_user, check validity, copy to internal structure */ | 540 | /* copy_from_user, check validity, copy to internal structure */ |
540 | struct video_window *vw; | 541 | struct video_window *vw; |
541 | int frame, err; | 542 | int frame, err; |
542 | vw = arg; | 543 | vw = arg; |
543 | 544 | ||
544 | if (vw->clipcount != 0) /* clipping not supported */ | 545 | if (vw->clipcount != 0) /* clipping not supported */ |
545 | return -EINVAL; | 546 | return -EINVAL; |
546 | 547 | ||
547 | if (vw->clips != NULL) /* clipping not supported */ | 548 | if (vw->clips != NULL) /* clipping not supported */ |
548 | return -EINVAL; | 549 | return -EINVAL; |
549 | 550 | ||
550 | /* Ensure that only this process can change the format. */ | 551 | /* Ensure that only this process can change the format. */ |
551 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | 552 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); |
552 | if(err != 0) | 553 | if(err != 0) |
553 | return err; | 554 | return err; |
554 | 555 | ||
555 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | 556 | cam->pixelformat = V4L2_PIX_FMT_JPEG; |
556 | 557 | ||
557 | /* Be sure to supply the Huffman tables, this isn't MJPEG */ | 558 | /* Be sure to supply the Huffman tables, this isn't MJPEG */ |
558 | cam->params.compression.inhibit_htables = 0; | 559 | cam->params.compression.inhibit_htables = 0; |
559 | 560 | ||
560 | /* we set the video window to something smaller or equal to what | 561 | /* we set the video window to something smaller or equal to what |
561 | * is requested by the user??? | 562 | * is requested by the user??? |
562 | */ | 563 | */ |
563 | DBG("Requested width = %d, height = %d\n", vw->width, vw->height); | 564 | DBG("Requested width = %d, height = %d\n", vw->width, vw->height); |
564 | if (vw->width != cam->vw.width || vw->height != cam->vw.height) { | 565 | if (vw->width != cam->vw.width || vw->height != cam->vw.height) { |
565 | cam->vw.width = vw->width; | 566 | cam->vw.width = vw->width; |
566 | cam->vw.height = vw->height; | 567 | cam->vw.height = vw->height; |
567 | cam->params.roi.width = vw->width; | 568 | cam->params.roi.width = vw->width; |
568 | cam->params.roi.height = vw->height; | 569 | cam->params.roi.height = vw->height; |
569 | cpia2_set_format(cam); | 570 | cpia2_set_format(cam); |
570 | } | 571 | } |
571 | 572 | ||
572 | for (frame = 0; frame < cam->num_frames; ++frame) { | 573 | for (frame = 0; frame < cam->num_frames; ++frame) { |
573 | if (cam->buffers[frame].status == FRAME_READING) | 574 | if (cam->buffers[frame].status == FRAME_READING) |
574 | if ((err = sync(cam, frame)) < 0) | 575 | if ((err = sync(cam, frame)) < 0) |
575 | return err; | 576 | return err; |
576 | 577 | ||
577 | cam->buffers[frame].status = FRAME_EMPTY; | 578 | cam->buffers[frame].status = FRAME_EMPTY; |
578 | } | 579 | } |
579 | 580 | ||
580 | return 0; | 581 | return 0; |
581 | } | 582 | } |
582 | 583 | ||
583 | /****************************************************************************** | 584 | /****************************************************************************** |
584 | * | 585 | * |
585 | * ioctl_get_mbuf | 586 | * ioctl_get_mbuf |
586 | * | 587 | * |
587 | *****************************************************************************/ | 588 | *****************************************************************************/ |
588 | static int ioctl_get_mbuf(void *arg, struct camera_data *cam) | 589 | static int ioctl_get_mbuf(void *arg, struct camera_data *cam) |
589 | { | 590 | { |
590 | struct video_mbuf *vm; | 591 | struct video_mbuf *vm; |
591 | int i; | 592 | int i; |
592 | vm = arg; | 593 | vm = arg; |
593 | 594 | ||
594 | memset(vm, 0, sizeof(*vm)); | 595 | memset(vm, 0, sizeof(*vm)); |
595 | vm->size = cam->frame_size*cam->num_frames; | 596 | vm->size = cam->frame_size*cam->num_frames; |
596 | vm->frames = cam->num_frames; | 597 | vm->frames = cam->num_frames; |
597 | for (i = 0; i < cam->num_frames; i++) | 598 | for (i = 0; i < cam->num_frames; i++) |
598 | vm->offsets[i] = cam->frame_size * i; | 599 | vm->offsets[i] = cam->frame_size * i; |
599 | 600 | ||
600 | return 0; | 601 | return 0; |
601 | } | 602 | } |
602 | 603 | ||
603 | /****************************************************************************** | 604 | /****************************************************************************** |
604 | * | 605 | * |
605 | * ioctl_mcapture | 606 | * ioctl_mcapture |
606 | * | 607 | * |
607 | *****************************************************************************/ | 608 | *****************************************************************************/ |
608 | static int ioctl_mcapture(void *arg, struct camera_data *cam, | 609 | static int ioctl_mcapture(void *arg, struct camera_data *cam, |
609 | struct cpia2_fh *fh) | 610 | struct cpia2_fh *fh) |
610 | { | 611 | { |
611 | struct video_mmap *vm; | 612 | struct video_mmap *vm; |
612 | int video_size, err; | 613 | int video_size, err; |
613 | vm = arg; | 614 | vm = arg; |
614 | 615 | ||
615 | if (vm->frame < 0 || vm->frame >= cam->num_frames) | 616 | if (vm->frame < 0 || vm->frame >= cam->num_frames) |
616 | return -EINVAL; | 617 | return -EINVAL; |
617 | 618 | ||
618 | /* set video size */ | 619 | /* set video size */ |
619 | video_size = cpia2_match_video_size(vm->width, vm->height); | 620 | video_size = cpia2_match_video_size(vm->width, vm->height); |
620 | if (cam->video_size < 0) { | 621 | if (cam->video_size < 0) { |
621 | return -EINVAL; | 622 | return -EINVAL; |
622 | } | 623 | } |
623 | 624 | ||
624 | /* Ensure that only this process can change the format. */ | 625 | /* Ensure that only this process can change the format. */ |
625 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | 626 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); |
626 | if(err != 0) | 627 | if(err != 0) |
627 | return err; | 628 | return err; |
628 | 629 | ||
629 | if (video_size != cam->video_size) { | 630 | if (video_size != cam->video_size) { |
630 | cam->video_size = video_size; | 631 | cam->video_size = video_size; |
631 | cam->params.roi.width = vm->width; | 632 | cam->params.roi.width = vm->width; |
632 | cam->params.roi.height = vm->height; | 633 | cam->params.roi.height = vm->height; |
633 | cpia2_set_format(cam); | 634 | cpia2_set_format(cam); |
634 | } | 635 | } |
635 | 636 | ||
636 | if (cam->buffers[vm->frame].status == FRAME_READING) | 637 | if (cam->buffers[vm->frame].status == FRAME_READING) |
637 | if ((err=sync(cam, vm->frame)) < 0) | 638 | if ((err=sync(cam, vm->frame)) < 0) |
638 | return err; | 639 | return err; |
639 | 640 | ||
640 | cam->buffers[vm->frame].status = FRAME_EMPTY; | 641 | cam->buffers[vm->frame].status = FRAME_EMPTY; |
641 | 642 | ||
642 | return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode); | 643 | return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode); |
643 | } | 644 | } |
644 | 645 | ||
645 | /****************************************************************************** | 646 | /****************************************************************************** |
646 | * | 647 | * |
647 | * ioctl_sync | 648 | * ioctl_sync |
648 | * | 649 | * |
649 | *****************************************************************************/ | 650 | *****************************************************************************/ |
650 | static int ioctl_sync(void *arg, struct camera_data *cam) | 651 | static int ioctl_sync(void *arg, struct camera_data *cam) |
651 | { | 652 | { |
652 | int frame; | 653 | int frame; |
653 | 654 | ||
654 | frame = *(int*)arg; | 655 | frame = *(int*)arg; |
655 | 656 | ||
656 | if (frame < 0 || frame >= cam->num_frames) | 657 | if (frame < 0 || frame >= cam->num_frames) |
657 | return -EINVAL; | 658 | return -EINVAL; |
658 | 659 | ||
659 | return sync(cam, frame); | 660 | return sync(cam, frame); |
660 | } | 661 | } |
661 | 662 | ||
662 | 663 | ||
663 | /****************************************************************************** | 664 | /****************************************************************************** |
664 | * | 665 | * |
665 | * ioctl_set_gpio | 666 | * ioctl_set_gpio |
666 | * | 667 | * |
667 | *****************************************************************************/ | 668 | *****************************************************************************/ |
668 | 669 | ||
669 | static int ioctl_set_gpio(void *arg, struct camera_data *cam) | 670 | static int ioctl_set_gpio(void *arg, struct camera_data *cam) |
670 | { | 671 | { |
671 | __u32 gpio_val; | 672 | __u32 gpio_val; |
672 | 673 | ||
673 | gpio_val = *(__u32*) arg; | 674 | gpio_val = *(__u32*) arg; |
674 | 675 | ||
675 | if (gpio_val &~ 0xFFU) | 676 | if (gpio_val &~ 0xFFU) |
676 | return -EINVAL; | 677 | return -EINVAL; |
677 | 678 | ||
678 | return cpia2_set_gpio(cam, (unsigned char)gpio_val); | 679 | return cpia2_set_gpio(cam, (unsigned char)gpio_val); |
679 | } | 680 | } |
680 | 681 | ||
681 | /****************************************************************************** | 682 | /****************************************************************************** |
682 | * | 683 | * |
683 | * ioctl_querycap | 684 | * ioctl_querycap |
684 | * | 685 | * |
685 | * V4L2 device capabilities | 686 | * V4L2 device capabilities |
686 | * | 687 | * |
687 | *****************************************************************************/ | 688 | *****************************************************************************/ |
688 | 689 | ||
689 | static int ioctl_querycap(void *arg, struct camera_data *cam) | 690 | static int ioctl_querycap(void *arg, struct camera_data *cam) |
690 | { | 691 | { |
691 | struct v4l2_capability *vc = arg; | 692 | struct v4l2_capability *vc = arg; |
692 | 693 | ||
693 | memset(vc, 0, sizeof(*vc)); | 694 | memset(vc, 0, sizeof(*vc)); |
694 | strcpy(vc->driver, "cpia2"); | 695 | strcpy(vc->driver, "cpia2"); |
695 | 696 | ||
696 | if (cam->params.pnp_id.product == 0x151) | 697 | if (cam->params.pnp_id.product == 0x151) |
697 | strcpy(vc->card, "QX5 Microscope"); | 698 | strcpy(vc->card, "QX5 Microscope"); |
698 | else | 699 | else |
699 | strcpy(vc->card, "CPiA2 Camera"); | 700 | strcpy(vc->card, "CPiA2 Camera"); |
700 | switch (cam->params.pnp_id.device_type) { | 701 | switch (cam->params.pnp_id.device_type) { |
701 | case DEVICE_STV_672: | 702 | case DEVICE_STV_672: |
702 | strcat(vc->card, " (672/"); | 703 | strcat(vc->card, " (672/"); |
703 | break; | 704 | break; |
704 | case DEVICE_STV_676: | 705 | case DEVICE_STV_676: |
705 | strcat(vc->card, " (676/"); | 706 | strcat(vc->card, " (676/"); |
706 | break; | 707 | break; |
707 | default: | 708 | default: |
708 | strcat(vc->card, " (???/"); | 709 | strcat(vc->card, " (???/"); |
709 | break; | 710 | break; |
710 | } | 711 | } |
711 | switch (cam->params.version.sensor_flags) { | 712 | switch (cam->params.version.sensor_flags) { |
712 | case CPIA2_VP_SENSOR_FLAGS_404: | 713 | case CPIA2_VP_SENSOR_FLAGS_404: |
713 | strcat(vc->card, "404)"); | 714 | strcat(vc->card, "404)"); |
714 | break; | 715 | break; |
715 | case CPIA2_VP_SENSOR_FLAGS_407: | 716 | case CPIA2_VP_SENSOR_FLAGS_407: |
716 | strcat(vc->card, "407)"); | 717 | strcat(vc->card, "407)"); |
717 | break; | 718 | break; |
718 | case CPIA2_VP_SENSOR_FLAGS_409: | 719 | case CPIA2_VP_SENSOR_FLAGS_409: |
719 | strcat(vc->card, "409)"); | 720 | strcat(vc->card, "409)"); |
720 | break; | 721 | break; |
721 | case CPIA2_VP_SENSOR_FLAGS_410: | 722 | case CPIA2_VP_SENSOR_FLAGS_410: |
722 | strcat(vc->card, "410)"); | 723 | strcat(vc->card, "410)"); |
723 | break; | 724 | break; |
724 | case CPIA2_VP_SENSOR_FLAGS_500: | 725 | case CPIA2_VP_SENSOR_FLAGS_500: |
725 | strcat(vc->card, "500)"); | 726 | strcat(vc->card, "500)"); |
726 | break; | 727 | break; |
727 | default: | 728 | default: |
728 | strcat(vc->card, "???)"); | 729 | strcat(vc->card, "???)"); |
729 | break; | 730 | break; |
730 | } | 731 | } |
731 | 732 | ||
732 | if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) | 733 | if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) |
733 | memset(vc->bus_info,0, sizeof(vc->bus_info)); | 734 | memset(vc->bus_info,0, sizeof(vc->bus_info)); |
734 | 735 | ||
735 | vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, | 736 | vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, |
736 | CPIA2_PATCH_VER); | 737 | CPIA2_PATCH_VER); |
737 | 738 | ||
738 | vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | | 739 | vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | |
739 | V4L2_CAP_READWRITE | | 740 | V4L2_CAP_READWRITE | |
740 | V4L2_CAP_STREAMING; | 741 | V4L2_CAP_STREAMING; |
741 | 742 | ||
742 | return 0; | 743 | return 0; |
743 | } | 744 | } |
744 | 745 | ||
745 | /****************************************************************************** | 746 | /****************************************************************************** |
746 | * | 747 | * |
747 | * ioctl_input | 748 | * ioctl_input |
748 | * | 749 | * |
749 | * V4L2 input get/set/enumerate | 750 | * V4L2 input get/set/enumerate |
750 | * | 751 | * |
751 | *****************************************************************************/ | 752 | *****************************************************************************/ |
752 | 753 | ||
753 | static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) | 754 | static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) |
754 | { | 755 | { |
755 | struct v4l2_input *i = arg; | 756 | struct v4l2_input *i = arg; |
756 | 757 | ||
757 | if(ioclt_nr != VIDIOC_G_INPUT) { | 758 | if(ioclt_nr != VIDIOC_G_INPUT) { |
758 | if (i->index != 0) | 759 | if (i->index != 0) |
759 | return -EINVAL; | 760 | return -EINVAL; |
760 | } | 761 | } |
761 | 762 | ||
762 | memset(i, 0, sizeof(*i)); | 763 | memset(i, 0, sizeof(*i)); |
763 | strcpy(i->name, "Camera"); | 764 | strcpy(i->name, "Camera"); |
764 | i->type = V4L2_INPUT_TYPE_CAMERA; | 765 | i->type = V4L2_INPUT_TYPE_CAMERA; |
765 | 766 | ||
766 | return 0; | 767 | return 0; |
767 | } | 768 | } |
768 | 769 | ||
769 | /****************************************************************************** | 770 | /****************************************************************************** |
770 | * | 771 | * |
771 | * ioctl_enum_fmt | 772 | * ioctl_enum_fmt |
772 | * | 773 | * |
773 | * V4L2 format enumerate | 774 | * V4L2 format enumerate |
774 | * | 775 | * |
775 | *****************************************************************************/ | 776 | *****************************************************************************/ |
776 | 777 | ||
777 | static int ioctl_enum_fmt(void *arg,struct camera_data *cam) | 778 | static int ioctl_enum_fmt(void *arg,struct camera_data *cam) |
778 | { | 779 | { |
779 | struct v4l2_fmtdesc *f = arg; | 780 | struct v4l2_fmtdesc *f = arg; |
780 | int index = f->index; | 781 | int index = f->index; |
781 | 782 | ||
782 | if (index < 0 || index > 1) | 783 | if (index < 0 || index > 1) |
783 | return -EINVAL; | 784 | return -EINVAL; |
784 | 785 | ||
785 | memset(f, 0, sizeof(*f)); | 786 | memset(f, 0, sizeof(*f)); |
786 | f->index = index; | 787 | f->index = index; |
787 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 788 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
788 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | 789 | f->flags = V4L2_FMT_FLAG_COMPRESSED; |
789 | switch(index) { | 790 | switch(index) { |
790 | case 0: | 791 | case 0: |
791 | strcpy(f->description, "MJPEG"); | 792 | strcpy(f->description, "MJPEG"); |
792 | f->pixelformat = V4L2_PIX_FMT_MJPEG; | 793 | f->pixelformat = V4L2_PIX_FMT_MJPEG; |
793 | break; | 794 | break; |
794 | case 1: | 795 | case 1: |
795 | strcpy(f->description, "JPEG"); | 796 | strcpy(f->description, "JPEG"); |
796 | f->pixelformat = V4L2_PIX_FMT_JPEG; | 797 | f->pixelformat = V4L2_PIX_FMT_JPEG; |
797 | break; | 798 | break; |
798 | default: | 799 | default: |
799 | return -EINVAL; | 800 | return -EINVAL; |
800 | } | 801 | } |
801 | 802 | ||
802 | return 0; | 803 | return 0; |
803 | } | 804 | } |
804 | 805 | ||
805 | /****************************************************************************** | 806 | /****************************************************************************** |
806 | * | 807 | * |
807 | * ioctl_try_fmt | 808 | * ioctl_try_fmt |
808 | * | 809 | * |
809 | * V4L2 format try | 810 | * V4L2 format try |
810 | * | 811 | * |
811 | *****************************************************************************/ | 812 | *****************************************************************************/ |
812 | 813 | ||
813 | static int ioctl_try_fmt(void *arg,struct camera_data *cam) | 814 | static int ioctl_try_fmt(void *arg,struct camera_data *cam) |
814 | { | 815 | { |
815 | struct v4l2_format *f = arg; | 816 | struct v4l2_format *f = arg; |
816 | 817 | ||
817 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 818 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
818 | return -EINVAL; | 819 | return -EINVAL; |
819 | 820 | ||
820 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | 821 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && |
821 | f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | 822 | f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) |
822 | return -EINVAL; | 823 | return -EINVAL; |
823 | 824 | ||
824 | f->fmt.pix.field = V4L2_FIELD_NONE; | 825 | f->fmt.pix.field = V4L2_FIELD_NONE; |
825 | f->fmt.pix.bytesperline = 0; | 826 | f->fmt.pix.bytesperline = 0; |
826 | f->fmt.pix.sizeimage = cam->frame_size; | 827 | f->fmt.pix.sizeimage = cam->frame_size; |
827 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | 828 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; |
828 | f->fmt.pix.priv = 0; | 829 | f->fmt.pix.priv = 0; |
829 | 830 | ||
830 | switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { | 831 | switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { |
831 | case VIDEOSIZE_VGA: | 832 | case VIDEOSIZE_VGA: |
832 | f->fmt.pix.width = 640; | 833 | f->fmt.pix.width = 640; |
833 | f->fmt.pix.height = 480; | 834 | f->fmt.pix.height = 480; |
834 | break; | 835 | break; |
835 | case VIDEOSIZE_CIF: | 836 | case VIDEOSIZE_CIF: |
836 | f->fmt.pix.width = 352; | 837 | f->fmt.pix.width = 352; |
837 | f->fmt.pix.height = 288; | 838 | f->fmt.pix.height = 288; |
838 | break; | 839 | break; |
839 | case VIDEOSIZE_QVGA: | 840 | case VIDEOSIZE_QVGA: |
840 | f->fmt.pix.width = 320; | 841 | f->fmt.pix.width = 320; |
841 | f->fmt.pix.height = 240; | 842 | f->fmt.pix.height = 240; |
842 | break; | 843 | break; |
843 | case VIDEOSIZE_288_216: | 844 | case VIDEOSIZE_288_216: |
844 | f->fmt.pix.width = 288; | 845 | f->fmt.pix.width = 288; |
845 | f->fmt.pix.height = 216; | 846 | f->fmt.pix.height = 216; |
846 | break; | 847 | break; |
847 | case VIDEOSIZE_256_192: | 848 | case VIDEOSIZE_256_192: |
848 | f->fmt.pix.width = 256; | 849 | f->fmt.pix.width = 256; |
849 | f->fmt.pix.height = 192; | 850 | f->fmt.pix.height = 192; |
850 | break; | 851 | break; |
851 | case VIDEOSIZE_224_168: | 852 | case VIDEOSIZE_224_168: |
852 | f->fmt.pix.width = 224; | 853 | f->fmt.pix.width = 224; |
853 | f->fmt.pix.height = 168; | 854 | f->fmt.pix.height = 168; |
854 | break; | 855 | break; |
855 | case VIDEOSIZE_192_144: | 856 | case VIDEOSIZE_192_144: |
856 | f->fmt.pix.width = 192; | 857 | f->fmt.pix.width = 192; |
857 | f->fmt.pix.height = 144; | 858 | f->fmt.pix.height = 144; |
858 | break; | 859 | break; |
859 | case VIDEOSIZE_QCIF: | 860 | case VIDEOSIZE_QCIF: |
860 | default: | 861 | default: |
861 | f->fmt.pix.width = 176; | 862 | f->fmt.pix.width = 176; |
862 | f->fmt.pix.height = 144; | 863 | f->fmt.pix.height = 144; |
863 | break; | 864 | break; |
864 | } | 865 | } |
865 | 866 | ||
866 | return 0; | 867 | return 0; |
867 | } | 868 | } |
868 | 869 | ||
869 | /****************************************************************************** | 870 | /****************************************************************************** |
870 | * | 871 | * |
871 | * ioctl_set_fmt | 872 | * ioctl_set_fmt |
872 | * | 873 | * |
873 | * V4L2 format set | 874 | * V4L2 format set |
874 | * | 875 | * |
875 | *****************************************************************************/ | 876 | *****************************************************************************/ |
876 | 877 | ||
877 | static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) | 878 | static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) |
878 | { | 879 | { |
879 | struct v4l2_format *f = arg; | 880 | struct v4l2_format *f = arg; |
880 | int err, frame; | 881 | int err, frame; |
881 | 882 | ||
882 | err = ioctl_try_fmt(arg, cam); | 883 | err = ioctl_try_fmt(arg, cam); |
883 | if(err != 0) | 884 | if(err != 0) |
884 | return err; | 885 | return err; |
885 | 886 | ||
886 | /* Ensure that only this process can change the format. */ | 887 | /* Ensure that only this process can change the format. */ |
887 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | 888 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); |
888 | if(err != 0) { | 889 | if(err != 0) { |
889 | return err; | 890 | return err; |
890 | } | 891 | } |
891 | 892 | ||
892 | cam->pixelformat = f->fmt.pix.pixelformat; | 893 | cam->pixelformat = f->fmt.pix.pixelformat; |
893 | 894 | ||
894 | /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle | 895 | /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle |
895 | * the missing Huffman table properly. */ | 896 | * the missing Huffman table properly. */ |
896 | cam->params.compression.inhibit_htables = 0; | 897 | cam->params.compression.inhibit_htables = 0; |
897 | /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ | 898 | /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ |
898 | 899 | ||
899 | /* we set the video window to something smaller or equal to what | 900 | /* we set the video window to something smaller or equal to what |
900 | * is requested by the user??? | 901 | * is requested by the user??? |
901 | */ | 902 | */ |
902 | DBG("Requested width = %d, height = %d\n", | 903 | DBG("Requested width = %d, height = %d\n", |
903 | f->fmt.pix.width, f->fmt.pix.height); | 904 | f->fmt.pix.width, f->fmt.pix.height); |
904 | if (f->fmt.pix.width != cam->vw.width || | 905 | if (f->fmt.pix.width != cam->vw.width || |
905 | f->fmt.pix.height != cam->vw.height) { | 906 | f->fmt.pix.height != cam->vw.height) { |
906 | cam->vw.width = f->fmt.pix.width; | 907 | cam->vw.width = f->fmt.pix.width; |
907 | cam->vw.height = f->fmt.pix.height; | 908 | cam->vw.height = f->fmt.pix.height; |
908 | cam->params.roi.width = f->fmt.pix.width; | 909 | cam->params.roi.width = f->fmt.pix.width; |
909 | cam->params.roi.height = f->fmt.pix.height; | 910 | cam->params.roi.height = f->fmt.pix.height; |
910 | cpia2_set_format(cam); | 911 | cpia2_set_format(cam); |
911 | } | 912 | } |
912 | 913 | ||
913 | for (frame = 0; frame < cam->num_frames; ++frame) { | 914 | for (frame = 0; frame < cam->num_frames; ++frame) { |
914 | if (cam->buffers[frame].status == FRAME_READING) | 915 | if (cam->buffers[frame].status == FRAME_READING) |
915 | if ((err = sync(cam, frame)) < 0) | 916 | if ((err = sync(cam, frame)) < 0) |
916 | return err; | 917 | return err; |
917 | 918 | ||
918 | cam->buffers[frame].status = FRAME_EMPTY; | 919 | cam->buffers[frame].status = FRAME_EMPTY; |
919 | } | 920 | } |
920 | 921 | ||
921 | return 0; | 922 | return 0; |
922 | } | 923 | } |
923 | 924 | ||
924 | /****************************************************************************** | 925 | /****************************************************************************** |
925 | * | 926 | * |
926 | * ioctl_get_fmt | 927 | * ioctl_get_fmt |
927 | * | 928 | * |
928 | * V4L2 format get | 929 | * V4L2 format get |
929 | * | 930 | * |
930 | *****************************************************************************/ | 931 | *****************************************************************************/ |
931 | 932 | ||
932 | static int ioctl_get_fmt(void *arg,struct camera_data *cam) | 933 | static int ioctl_get_fmt(void *arg,struct camera_data *cam) |
933 | { | 934 | { |
934 | struct v4l2_format *f = arg; | 935 | struct v4l2_format *f = arg; |
935 | 936 | ||
936 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 937 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
937 | return -EINVAL; | 938 | return -EINVAL; |
938 | 939 | ||
939 | f->fmt.pix.width = cam->vw.width; | 940 | f->fmt.pix.width = cam->vw.width; |
940 | f->fmt.pix.height = cam->vw.height; | 941 | f->fmt.pix.height = cam->vw.height; |
941 | f->fmt.pix.pixelformat = cam->pixelformat; | 942 | f->fmt.pix.pixelformat = cam->pixelformat; |
942 | f->fmt.pix.field = V4L2_FIELD_NONE; | 943 | f->fmt.pix.field = V4L2_FIELD_NONE; |
943 | f->fmt.pix.bytesperline = 0; | 944 | f->fmt.pix.bytesperline = 0; |
944 | f->fmt.pix.sizeimage = cam->frame_size; | 945 | f->fmt.pix.sizeimage = cam->frame_size; |
945 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | 946 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; |
946 | f->fmt.pix.priv = 0; | 947 | f->fmt.pix.priv = 0; |
947 | 948 | ||
948 | return 0; | 949 | return 0; |
949 | } | 950 | } |
950 | 951 | ||
951 | /****************************************************************************** | 952 | /****************************************************************************** |
952 | * | 953 | * |
953 | * ioctl_cropcap | 954 | * ioctl_cropcap |
954 | * | 955 | * |
955 | * V4L2 query cropping capabilities | 956 | * V4L2 query cropping capabilities |
956 | * NOTE: cropping is currently disabled | 957 | * NOTE: cropping is currently disabled |
957 | * | 958 | * |
958 | *****************************************************************************/ | 959 | *****************************************************************************/ |
959 | 960 | ||
960 | static int ioctl_cropcap(void *arg,struct camera_data *cam) | 961 | static int ioctl_cropcap(void *arg,struct camera_data *cam) |
961 | { | 962 | { |
962 | struct v4l2_cropcap *c = arg; | 963 | struct v4l2_cropcap *c = arg; |
963 | 964 | ||
964 | if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 965 | if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
965 | return -EINVAL; | 966 | return -EINVAL; |
966 | 967 | ||
967 | c->bounds.left = 0; | 968 | c->bounds.left = 0; |
968 | c->bounds.top = 0; | 969 | c->bounds.top = 0; |
969 | c->bounds.width = cam->vw.width; | 970 | c->bounds.width = cam->vw.width; |
970 | c->bounds.height = cam->vw.height; | 971 | c->bounds.height = cam->vw.height; |
971 | c->defrect.left = 0; | 972 | c->defrect.left = 0; |
972 | c->defrect.top = 0; | 973 | c->defrect.top = 0; |
973 | c->defrect.width = cam->vw.width; | 974 | c->defrect.width = cam->vw.width; |
974 | c->defrect.height = cam->vw.height; | 975 | c->defrect.height = cam->vw.height; |
975 | c->pixelaspect.numerator = 1; | 976 | c->pixelaspect.numerator = 1; |
976 | c->pixelaspect.denominator = 1; | 977 | c->pixelaspect.denominator = 1; |
977 | 978 | ||
978 | return 0; | 979 | return 0; |
979 | } | 980 | } |
980 | 981 | ||
981 | /****************************************************************************** | 982 | /****************************************************************************** |
982 | * | 983 | * |
983 | * ioctl_queryctrl | 984 | * ioctl_queryctrl |
984 | * | 985 | * |
985 | * V4L2 query possible control variables | 986 | * V4L2 query possible control variables |
986 | * | 987 | * |
987 | *****************************************************************************/ | 988 | *****************************************************************************/ |
988 | 989 | ||
989 | static int ioctl_queryctrl(void *arg,struct camera_data *cam) | 990 | static int ioctl_queryctrl(void *arg,struct camera_data *cam) |
990 | { | 991 | { |
991 | struct v4l2_queryctrl *c = arg; | 992 | struct v4l2_queryctrl *c = arg; |
992 | int i; | 993 | int i; |
993 | 994 | ||
994 | for(i=0; i<NUM_CONTROLS; ++i) { | 995 | for(i=0; i<NUM_CONTROLS; ++i) { |
995 | if(c->id == controls[i].id) { | 996 | if(c->id == controls[i].id) { |
996 | memcpy(c, controls+i, sizeof(*c)); | 997 | memcpy(c, controls+i, sizeof(*c)); |
997 | break; | 998 | break; |
998 | } | 999 | } |
999 | } | 1000 | } |
1000 | 1001 | ||
1001 | if(i == NUM_CONTROLS) | 1002 | if(i == NUM_CONTROLS) |
1002 | return -EINVAL; | 1003 | return -EINVAL; |
1003 | 1004 | ||
1004 | /* Some devices have additional limitations */ | 1005 | /* Some devices have additional limitations */ |
1005 | switch(c->id) { | 1006 | switch(c->id) { |
1006 | case V4L2_CID_BRIGHTNESS: | 1007 | case V4L2_CID_BRIGHTNESS: |
1007 | /*** | 1008 | /*** |
1008 | * Don't let the register be set to zero - bug in VP4 | 1009 | * Don't let the register be set to zero - bug in VP4 |
1009 | * flash of full brightness | 1010 | * flash of full brightness |
1010 | ***/ | 1011 | ***/ |
1011 | if (cam->params.pnp_id.device_type == DEVICE_STV_672) | 1012 | if (cam->params.pnp_id.device_type == DEVICE_STV_672) |
1012 | c->minimum = 1; | 1013 | c->minimum = 1; |
1013 | break; | 1014 | break; |
1014 | case V4L2_CID_VFLIP: | 1015 | case V4L2_CID_VFLIP: |
1015 | // VP5 Only | 1016 | // VP5 Only |
1016 | if(cam->params.pnp_id.device_type == DEVICE_STV_672) | 1017 | if(cam->params.pnp_id.device_type == DEVICE_STV_672) |
1017 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | 1018 | c->flags |= V4L2_CTRL_FLAG_DISABLED; |
1018 | break; | 1019 | break; |
1019 | case CPIA2_CID_FRAMERATE: | 1020 | case CPIA2_CID_FRAMERATE: |
1020 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | 1021 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && |
1021 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | 1022 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ |
1022 | // Maximum 15fps | 1023 | // Maximum 15fps |
1023 | for(i=0; i<c->maximum; ++i) { | 1024 | for(i=0; i<c->maximum; ++i) { |
1024 | if(framerate_controls[i].value == | 1025 | if(framerate_controls[i].value == |
1025 | CPIA2_VP_FRAMERATE_15) { | 1026 | CPIA2_VP_FRAMERATE_15) { |
1026 | c->maximum = i; | 1027 | c->maximum = i; |
1027 | c->default_value = i; | 1028 | c->default_value = i; |
1028 | } | 1029 | } |
1029 | } | 1030 | } |
1030 | } | 1031 | } |
1031 | break; | 1032 | break; |
1032 | case CPIA2_CID_FLICKER_MODE: | 1033 | case CPIA2_CID_FLICKER_MODE: |
1033 | // Flicker control only valid for 672. | 1034 | // Flicker control only valid for 672. |
1034 | if(cam->params.pnp_id.device_type != DEVICE_STV_672) | 1035 | if(cam->params.pnp_id.device_type != DEVICE_STV_672) |
1035 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | 1036 | c->flags |= V4L2_CTRL_FLAG_DISABLED; |
1036 | break; | 1037 | break; |
1037 | case CPIA2_CID_LIGHTS: | 1038 | case CPIA2_CID_LIGHTS: |
1038 | // Light control only valid for the QX5 Microscope. | 1039 | // Light control only valid for the QX5 Microscope. |
1039 | if(cam->params.pnp_id.product != 0x151) | 1040 | if(cam->params.pnp_id.product != 0x151) |
1040 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | 1041 | c->flags |= V4L2_CTRL_FLAG_DISABLED; |
1041 | break; | 1042 | break; |
1042 | default: | 1043 | default: |
1043 | break; | 1044 | break; |
1044 | } | 1045 | } |
1045 | 1046 | ||
1046 | return 0; | 1047 | return 0; |
1047 | } | 1048 | } |
1048 | 1049 | ||
1049 | /****************************************************************************** | 1050 | /****************************************************************************** |
1050 | * | 1051 | * |
1051 | * ioctl_querymenu | 1052 | * ioctl_querymenu |
1052 | * | 1053 | * |
1053 | * V4L2 query possible control variables | 1054 | * V4L2 query possible control variables |
1054 | * | 1055 | * |
1055 | *****************************************************************************/ | 1056 | *****************************************************************************/ |
1056 | 1057 | ||
1057 | static int ioctl_querymenu(void *arg,struct camera_data *cam) | 1058 | static int ioctl_querymenu(void *arg,struct camera_data *cam) |
1058 | { | 1059 | { |
1059 | struct v4l2_querymenu *m = arg; | 1060 | struct v4l2_querymenu *m = arg; |
1060 | 1061 | ||
1061 | memset(m->name, 0, sizeof(m->name)); | 1062 | memset(m->name, 0, sizeof(m->name)); |
1062 | m->reserved = 0; | 1063 | m->reserved = 0; |
1063 | 1064 | ||
1064 | switch(m->id) { | 1065 | switch(m->id) { |
1065 | case CPIA2_CID_FLICKER_MODE: | 1066 | case CPIA2_CID_FLICKER_MODE: |
1066 | if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) | 1067 | if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) |
1067 | return -EINVAL; | 1068 | return -EINVAL; |
1068 | 1069 | ||
1069 | strcpy(m->name, flicker_controls[m->index].name); | 1070 | strcpy(m->name, flicker_controls[m->index].name); |
1070 | break; | 1071 | break; |
1071 | case CPIA2_CID_FRAMERATE: | 1072 | case CPIA2_CID_FRAMERATE: |
1072 | { | 1073 | { |
1073 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | 1074 | int maximum = NUM_FRAMERATE_CONTROLS - 1; |
1074 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | 1075 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && |
1075 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | 1076 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ |
1076 | // Maximum 15fps | 1077 | // Maximum 15fps |
1077 | int i; | 1078 | int i; |
1078 | for(i=0; i<maximum; ++i) { | 1079 | for(i=0; i<maximum; ++i) { |
1079 | if(framerate_controls[i].value == | 1080 | if(framerate_controls[i].value == |
1080 | CPIA2_VP_FRAMERATE_15) | 1081 | CPIA2_VP_FRAMERATE_15) |
1081 | maximum = i; | 1082 | maximum = i; |
1082 | } | 1083 | } |
1083 | } | 1084 | } |
1084 | if(m->index < 0 || m->index > maximum) | 1085 | if(m->index < 0 || m->index > maximum) |
1085 | return -EINVAL; | 1086 | return -EINVAL; |
1086 | 1087 | ||
1087 | strcpy(m->name, framerate_controls[m->index].name); | 1088 | strcpy(m->name, framerate_controls[m->index].name); |
1088 | break; | 1089 | break; |
1089 | } | 1090 | } |
1090 | case CPIA2_CID_LIGHTS: | 1091 | case CPIA2_CID_LIGHTS: |
1091 | if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) | 1092 | if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) |
1092 | return -EINVAL; | 1093 | return -EINVAL; |
1093 | 1094 | ||
1094 | strcpy(m->name, lights_controls[m->index].name); | 1095 | strcpy(m->name, lights_controls[m->index].name); |
1095 | break; | 1096 | break; |
1096 | default: | 1097 | default: |
1097 | return -EINVAL; | 1098 | return -EINVAL; |
1098 | } | 1099 | } |
1099 | 1100 | ||
1100 | return 0; | 1101 | return 0; |
1101 | } | 1102 | } |
1102 | 1103 | ||
1103 | /****************************************************************************** | 1104 | /****************************************************************************** |
1104 | * | 1105 | * |
1105 | * ioctl_g_ctrl | 1106 | * ioctl_g_ctrl |
1106 | * | 1107 | * |
1107 | * V4L2 get the value of a control variable | 1108 | * V4L2 get the value of a control variable |
1108 | * | 1109 | * |
1109 | *****************************************************************************/ | 1110 | *****************************************************************************/ |
1110 | 1111 | ||
1111 | static int ioctl_g_ctrl(void *arg,struct camera_data *cam) | 1112 | static int ioctl_g_ctrl(void *arg,struct camera_data *cam) |
1112 | { | 1113 | { |
1113 | struct v4l2_control *c = arg; | 1114 | struct v4l2_control *c = arg; |
1114 | 1115 | ||
1115 | switch(c->id) { | 1116 | switch(c->id) { |
1116 | case V4L2_CID_BRIGHTNESS: | 1117 | case V4L2_CID_BRIGHTNESS: |
1117 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, | 1118 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, |
1118 | TRANSFER_READ, 0); | 1119 | TRANSFER_READ, 0); |
1119 | c->value = cam->params.color_params.brightness; | 1120 | c->value = cam->params.color_params.brightness; |
1120 | break; | 1121 | break; |
1121 | case V4L2_CID_CONTRAST: | 1122 | case V4L2_CID_CONTRAST: |
1122 | cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, | 1123 | cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, |
1123 | TRANSFER_READ, 0); | 1124 | TRANSFER_READ, 0); |
1124 | c->value = cam->params.color_params.contrast; | 1125 | c->value = cam->params.color_params.contrast; |
1125 | break; | 1126 | break; |
1126 | case V4L2_CID_SATURATION: | 1127 | case V4L2_CID_SATURATION: |
1127 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, | 1128 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, |
1128 | TRANSFER_READ, 0); | 1129 | TRANSFER_READ, 0); |
1129 | c->value = cam->params.color_params.saturation; | 1130 | c->value = cam->params.color_params.saturation; |
1130 | break; | 1131 | break; |
1131 | case V4L2_CID_HFLIP: | 1132 | case V4L2_CID_HFLIP: |
1132 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | 1133 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, |
1133 | TRANSFER_READ, 0); | 1134 | TRANSFER_READ, 0); |
1134 | c->value = (cam->params.vp_params.user_effects & | 1135 | c->value = (cam->params.vp_params.user_effects & |
1135 | CPIA2_VP_USER_EFFECTS_MIRROR) != 0; | 1136 | CPIA2_VP_USER_EFFECTS_MIRROR) != 0; |
1136 | break; | 1137 | break; |
1137 | case V4L2_CID_VFLIP: | 1138 | case V4L2_CID_VFLIP: |
1138 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | 1139 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, |
1139 | TRANSFER_READ, 0); | 1140 | TRANSFER_READ, 0); |
1140 | c->value = (cam->params.vp_params.user_effects & | 1141 | c->value = (cam->params.vp_params.user_effects & |
1141 | CPIA2_VP_USER_EFFECTS_FLIP) != 0; | 1142 | CPIA2_VP_USER_EFFECTS_FLIP) != 0; |
1142 | break; | 1143 | break; |
1143 | case CPIA2_CID_TARGET_KB: | 1144 | case CPIA2_CID_TARGET_KB: |
1144 | c->value = cam->params.vc_params.target_kb; | 1145 | c->value = cam->params.vc_params.target_kb; |
1145 | break; | 1146 | break; |
1146 | case CPIA2_CID_GPIO: | 1147 | case CPIA2_CID_GPIO: |
1147 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | 1148 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, |
1148 | TRANSFER_READ, 0); | 1149 | TRANSFER_READ, 0); |
1149 | c->value = cam->params.vp_params.gpio_data; | 1150 | c->value = cam->params.vp_params.gpio_data; |
1150 | break; | 1151 | break; |
1151 | case CPIA2_CID_FLICKER_MODE: | 1152 | case CPIA2_CID_FLICKER_MODE: |
1152 | { | 1153 | { |
1153 | int i, mode; | 1154 | int i, mode; |
1154 | cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, | 1155 | cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, |
1155 | TRANSFER_READ, 0); | 1156 | TRANSFER_READ, 0); |
1156 | if(cam->params.flicker_control.cam_register & | 1157 | if(cam->params.flicker_control.cam_register & |
1157 | CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { | 1158 | CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { |
1158 | mode = NEVER_FLICKER; | 1159 | mode = NEVER_FLICKER; |
1159 | } else { | 1160 | } else { |
1160 | if(cam->params.flicker_control.cam_register & | 1161 | if(cam->params.flicker_control.cam_register & |
1161 | CPIA2_VP_FLICKER_MODES_50HZ) { | 1162 | CPIA2_VP_FLICKER_MODES_50HZ) { |
1162 | mode = FLICKER_50; | 1163 | mode = FLICKER_50; |
1163 | } else { | 1164 | } else { |
1164 | mode = FLICKER_60; | 1165 | mode = FLICKER_60; |
1165 | } | 1166 | } |
1166 | } | 1167 | } |
1167 | for(i=0; i<NUM_FLICKER_CONTROLS; i++) { | 1168 | for(i=0; i<NUM_FLICKER_CONTROLS; i++) { |
1168 | if(flicker_controls[i].value == mode) { | 1169 | if(flicker_controls[i].value == mode) { |
1169 | c->value = i; | 1170 | c->value = i; |
1170 | break; | 1171 | break; |
1171 | } | 1172 | } |
1172 | } | 1173 | } |
1173 | if(i == NUM_FLICKER_CONTROLS) | 1174 | if(i == NUM_FLICKER_CONTROLS) |
1174 | return -EINVAL; | 1175 | return -EINVAL; |
1175 | break; | 1176 | break; |
1176 | } | 1177 | } |
1177 | case CPIA2_CID_FRAMERATE: | 1178 | case CPIA2_CID_FRAMERATE: |
1178 | { | 1179 | { |
1179 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | 1180 | int maximum = NUM_FRAMERATE_CONTROLS - 1; |
1180 | int i; | 1181 | int i; |
1181 | for(i=0; i<= maximum; i++) { | 1182 | for(i=0; i<= maximum; i++) { |
1182 | if(cam->params.vp_params.frame_rate == | 1183 | if(cam->params.vp_params.frame_rate == |
1183 | framerate_controls[i].value) | 1184 | framerate_controls[i].value) |
1184 | break; | 1185 | break; |
1185 | } | 1186 | } |
1186 | if(i > maximum) | 1187 | if(i > maximum) |
1187 | return -EINVAL; | 1188 | return -EINVAL; |
1188 | c->value = i; | 1189 | c->value = i; |
1189 | break; | 1190 | break; |
1190 | } | 1191 | } |
1191 | case CPIA2_CID_USB_ALT: | 1192 | case CPIA2_CID_USB_ALT: |
1192 | c->value = cam->params.camera_state.stream_mode; | 1193 | c->value = cam->params.camera_state.stream_mode; |
1193 | break; | 1194 | break; |
1194 | case CPIA2_CID_LIGHTS: | 1195 | case CPIA2_CID_LIGHTS: |
1195 | { | 1196 | { |
1196 | int i; | 1197 | int i; |
1197 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | 1198 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, |
1198 | TRANSFER_READ, 0); | 1199 | TRANSFER_READ, 0); |
1199 | for(i=0; i<NUM_LIGHTS_CONTROLS; i++) { | 1200 | for(i=0; i<NUM_LIGHTS_CONTROLS; i++) { |
1200 | if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) == | 1201 | if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) == |
1201 | lights_controls[i].value) { | 1202 | lights_controls[i].value) { |
1202 | break; | 1203 | break; |
1203 | } | 1204 | } |
1204 | } | 1205 | } |
1205 | if(i == NUM_LIGHTS_CONTROLS) | 1206 | if(i == NUM_LIGHTS_CONTROLS) |
1206 | return -EINVAL; | 1207 | return -EINVAL; |
1207 | c->value = i; | 1208 | c->value = i; |
1208 | break; | 1209 | break; |
1209 | } | 1210 | } |
1210 | case CPIA2_CID_RESET_CAMERA: | 1211 | case CPIA2_CID_RESET_CAMERA: |
1211 | return -EINVAL; | 1212 | return -EINVAL; |
1212 | default: | 1213 | default: |
1213 | return -EINVAL; | 1214 | return -EINVAL; |
1214 | } | 1215 | } |
1215 | 1216 | ||
1216 | DBG("Get control id:%d, value:%d\n", c->id, c->value); | 1217 | DBG("Get control id:%d, value:%d\n", c->id, c->value); |
1217 | 1218 | ||
1218 | return 0; | 1219 | return 0; |
1219 | } | 1220 | } |
1220 | 1221 | ||
1221 | /****************************************************************************** | 1222 | /****************************************************************************** |
1222 | * | 1223 | * |
1223 | * ioctl_s_ctrl | 1224 | * ioctl_s_ctrl |
1224 | * | 1225 | * |
1225 | * V4L2 set the value of a control variable | 1226 | * V4L2 set the value of a control variable |
1226 | * | 1227 | * |
1227 | *****************************************************************************/ | 1228 | *****************************************************************************/ |
1228 | 1229 | ||
1229 | static int ioctl_s_ctrl(void *arg,struct camera_data *cam) | 1230 | static int ioctl_s_ctrl(void *arg,struct camera_data *cam) |
1230 | { | 1231 | { |
1231 | struct v4l2_control *c = arg; | 1232 | struct v4l2_control *c = arg; |
1232 | int i; | 1233 | int i; |
1233 | int retval = 0; | 1234 | int retval = 0; |
1234 | 1235 | ||
1235 | DBG("Set control id:%d, value:%d\n", c->id, c->value); | 1236 | DBG("Set control id:%d, value:%d\n", c->id, c->value); |
1236 | 1237 | ||
1237 | /* Check that the value is in range */ | 1238 | /* Check that the value is in range */ |
1238 | for(i=0; i<NUM_CONTROLS; i++) { | 1239 | for(i=0; i<NUM_CONTROLS; i++) { |
1239 | if(c->id == controls[i].id) { | 1240 | if(c->id == controls[i].id) { |
1240 | if(c->value < controls[i].minimum || | 1241 | if(c->value < controls[i].minimum || |
1241 | c->value > controls[i].maximum) { | 1242 | c->value > controls[i].maximum) { |
1242 | return -EINVAL; | 1243 | return -EINVAL; |
1243 | } | 1244 | } |
1244 | break; | 1245 | break; |
1245 | } | 1246 | } |
1246 | } | 1247 | } |
1247 | if(i == NUM_CONTROLS) | 1248 | if(i == NUM_CONTROLS) |
1248 | return -EINVAL; | 1249 | return -EINVAL; |
1249 | 1250 | ||
1250 | switch(c->id) { | 1251 | switch(c->id) { |
1251 | case V4L2_CID_BRIGHTNESS: | 1252 | case V4L2_CID_BRIGHTNESS: |
1252 | cpia2_set_brightness(cam, c->value); | 1253 | cpia2_set_brightness(cam, c->value); |
1253 | break; | 1254 | break; |
1254 | case V4L2_CID_CONTRAST: | 1255 | case V4L2_CID_CONTRAST: |
1255 | cpia2_set_contrast(cam, c->value); | 1256 | cpia2_set_contrast(cam, c->value); |
1256 | break; | 1257 | break; |
1257 | case V4L2_CID_SATURATION: | 1258 | case V4L2_CID_SATURATION: |
1258 | cpia2_set_saturation(cam, c->value); | 1259 | cpia2_set_saturation(cam, c->value); |
1259 | break; | 1260 | break; |
1260 | case V4L2_CID_HFLIP: | 1261 | case V4L2_CID_HFLIP: |
1261 | cpia2_set_property_mirror(cam, c->value); | 1262 | cpia2_set_property_mirror(cam, c->value); |
1262 | break; | 1263 | break; |
1263 | case V4L2_CID_VFLIP: | 1264 | case V4L2_CID_VFLIP: |
1264 | cpia2_set_property_flip(cam, c->value); | 1265 | cpia2_set_property_flip(cam, c->value); |
1265 | break; | 1266 | break; |
1266 | case CPIA2_CID_TARGET_KB: | 1267 | case CPIA2_CID_TARGET_KB: |
1267 | retval = cpia2_set_target_kb(cam, c->value); | 1268 | retval = cpia2_set_target_kb(cam, c->value); |
1268 | break; | 1269 | break; |
1269 | case CPIA2_CID_GPIO: | 1270 | case CPIA2_CID_GPIO: |
1270 | retval = cpia2_set_gpio(cam, c->value); | 1271 | retval = cpia2_set_gpio(cam, c->value); |
1271 | break; | 1272 | break; |
1272 | case CPIA2_CID_FLICKER_MODE: | 1273 | case CPIA2_CID_FLICKER_MODE: |
1273 | retval = cpia2_set_flicker_mode(cam, | 1274 | retval = cpia2_set_flicker_mode(cam, |
1274 | flicker_controls[c->value].value); | 1275 | flicker_controls[c->value].value); |
1275 | break; | 1276 | break; |
1276 | case CPIA2_CID_FRAMERATE: | 1277 | case CPIA2_CID_FRAMERATE: |
1277 | retval = cpia2_set_fps(cam, framerate_controls[c->value].value); | 1278 | retval = cpia2_set_fps(cam, framerate_controls[c->value].value); |
1278 | break; | 1279 | break; |
1279 | case CPIA2_CID_USB_ALT: | 1280 | case CPIA2_CID_USB_ALT: |
1280 | retval = cpia2_usb_change_streaming_alternate(cam, c->value); | 1281 | retval = cpia2_usb_change_streaming_alternate(cam, c->value); |
1281 | break; | 1282 | break; |
1282 | case CPIA2_CID_LIGHTS: | 1283 | case CPIA2_CID_LIGHTS: |
1283 | retval = cpia2_set_gpio(cam, lights_controls[c->value].value); | 1284 | retval = cpia2_set_gpio(cam, lights_controls[c->value].value); |
1284 | break; | 1285 | break; |
1285 | case CPIA2_CID_RESET_CAMERA: | 1286 | case CPIA2_CID_RESET_CAMERA: |
1286 | cpia2_usb_stream_pause(cam); | 1287 | cpia2_usb_stream_pause(cam); |
1287 | cpia2_reset_camera(cam); | 1288 | cpia2_reset_camera(cam); |
1288 | cpia2_usb_stream_resume(cam); | 1289 | cpia2_usb_stream_resume(cam); |
1289 | break; | 1290 | break; |
1290 | default: | 1291 | default: |
1291 | retval = -EINVAL; | 1292 | retval = -EINVAL; |
1292 | } | 1293 | } |
1293 | 1294 | ||
1294 | return retval; | 1295 | return retval; |
1295 | } | 1296 | } |
1296 | 1297 | ||
1297 | /****************************************************************************** | 1298 | /****************************************************************************** |
1298 | * | 1299 | * |
1299 | * ioctl_g_jpegcomp | 1300 | * ioctl_g_jpegcomp |
1300 | * | 1301 | * |
1301 | * V4L2 get the JPEG compression parameters | 1302 | * V4L2 get the JPEG compression parameters |
1302 | * | 1303 | * |
1303 | *****************************************************************************/ | 1304 | *****************************************************************************/ |
1304 | 1305 | ||
1305 | static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) | 1306 | static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) |
1306 | { | 1307 | { |
1307 | struct v4l2_jpegcompression *parms = arg; | 1308 | struct v4l2_jpegcompression *parms = arg; |
1308 | 1309 | ||
1309 | memset(parms, 0, sizeof(*parms)); | 1310 | memset(parms, 0, sizeof(*parms)); |
1310 | 1311 | ||
1311 | parms->quality = 80; // TODO: Can this be made meaningful? | 1312 | parms->quality = 80; // TODO: Can this be made meaningful? |
1312 | 1313 | ||
1313 | parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; | 1314 | parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; |
1314 | if(!cam->params.compression.inhibit_htables) { | 1315 | if(!cam->params.compression.inhibit_htables) { |
1315 | parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; | 1316 | parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; |
1316 | } | 1317 | } |
1317 | 1318 | ||
1318 | parms->APPn = cam->APPn; | 1319 | parms->APPn = cam->APPn; |
1319 | parms->APP_len = cam->APP_len; | 1320 | parms->APP_len = cam->APP_len; |
1320 | if(cam->APP_len > 0) { | 1321 | if(cam->APP_len > 0) { |
1321 | memcpy(parms->APP_data, cam->APP_data, cam->APP_len); | 1322 | memcpy(parms->APP_data, cam->APP_data, cam->APP_len); |
1322 | parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; | 1323 | parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; |
1323 | } | 1324 | } |
1324 | 1325 | ||
1325 | parms->COM_len = cam->COM_len; | 1326 | parms->COM_len = cam->COM_len; |
1326 | if(cam->COM_len > 0) { | 1327 | if(cam->COM_len > 0) { |
1327 | memcpy(parms->COM_data, cam->COM_data, cam->COM_len); | 1328 | memcpy(parms->COM_data, cam->COM_data, cam->COM_len); |
1328 | parms->jpeg_markers |= JPEG_MARKER_COM; | 1329 | parms->jpeg_markers |= JPEG_MARKER_COM; |
1329 | } | 1330 | } |
1330 | 1331 | ||
1331 | DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", | 1332 | DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", |
1332 | parms->APP_len, parms->COM_len); | 1333 | parms->APP_len, parms->COM_len); |
1333 | 1334 | ||
1334 | return 0; | 1335 | return 0; |
1335 | } | 1336 | } |
1336 | 1337 | ||
1337 | /****************************************************************************** | 1338 | /****************************************************************************** |
1338 | * | 1339 | * |
1339 | * ioctl_s_jpegcomp | 1340 | * ioctl_s_jpegcomp |
1340 | * | 1341 | * |
1341 | * V4L2 set the JPEG compression parameters | 1342 | * V4L2 set the JPEG compression parameters |
1342 | * NOTE: quality and some jpeg_markers are ignored. | 1343 | * NOTE: quality and some jpeg_markers are ignored. |
1343 | * | 1344 | * |
1344 | *****************************************************************************/ | 1345 | *****************************************************************************/ |
1345 | 1346 | ||
1346 | static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) | 1347 | static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) |
1347 | { | 1348 | { |
1348 | struct v4l2_jpegcompression *parms = arg; | 1349 | struct v4l2_jpegcompression *parms = arg; |
1349 | 1350 | ||
1350 | DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", | 1351 | DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", |
1351 | parms->APP_len, parms->COM_len); | 1352 | parms->APP_len, parms->COM_len); |
1352 | 1353 | ||
1353 | cam->params.compression.inhibit_htables = | 1354 | cam->params.compression.inhibit_htables = |
1354 | !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); | 1355 | !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); |
1355 | 1356 | ||
1356 | if(parms->APP_len != 0) { | 1357 | if(parms->APP_len != 0) { |
1357 | if(parms->APP_len > 0 && | 1358 | if(parms->APP_len > 0 && |
1358 | parms->APP_len <= sizeof(cam->APP_data) && | 1359 | parms->APP_len <= sizeof(cam->APP_data) && |
1359 | parms->APPn >= 0 && parms->APPn <= 15) { | 1360 | parms->APPn >= 0 && parms->APPn <= 15) { |
1360 | cam->APPn = parms->APPn; | 1361 | cam->APPn = parms->APPn; |
1361 | cam->APP_len = parms->APP_len; | 1362 | cam->APP_len = parms->APP_len; |
1362 | memcpy(cam->APP_data, parms->APP_data, parms->APP_len); | 1363 | memcpy(cam->APP_data, parms->APP_data, parms->APP_len); |
1363 | } else { | 1364 | } else { |
1364 | LOG("Bad APPn Params n=%d len=%d\n", | 1365 | LOG("Bad APPn Params n=%d len=%d\n", |
1365 | parms->APPn, parms->APP_len); | 1366 | parms->APPn, parms->APP_len); |
1366 | return -EINVAL; | 1367 | return -EINVAL; |
1367 | } | 1368 | } |
1368 | } else { | 1369 | } else { |
1369 | cam->APP_len = 0; | 1370 | cam->APP_len = 0; |
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | if(parms->COM_len != 0) { | 1373 | if(parms->COM_len != 0) { |
1373 | if(parms->COM_len > 0 && | 1374 | if(parms->COM_len > 0 && |
1374 | parms->COM_len <= sizeof(cam->COM_data)) { | 1375 | parms->COM_len <= sizeof(cam->COM_data)) { |
1375 | cam->COM_len = parms->COM_len; | 1376 | cam->COM_len = parms->COM_len; |
1376 | memcpy(cam->COM_data, parms->COM_data, parms->COM_len); | 1377 | memcpy(cam->COM_data, parms->COM_data, parms->COM_len); |
1377 | } else { | 1378 | } else { |
1378 | LOG("Bad COM_len=%d\n", parms->COM_len); | 1379 | LOG("Bad COM_len=%d\n", parms->COM_len); |
1379 | return -EINVAL; | 1380 | return -EINVAL; |
1380 | } | 1381 | } |
1381 | } | 1382 | } |
1382 | 1383 | ||
1383 | return 0; | 1384 | return 0; |
1384 | } | 1385 | } |
1385 | 1386 | ||
1386 | /****************************************************************************** | 1387 | /****************************************************************************** |
1387 | * | 1388 | * |
1388 | * ioctl_reqbufs | 1389 | * ioctl_reqbufs |
1389 | * | 1390 | * |
1390 | * V4L2 Initiate memory mapping. | 1391 | * V4L2 Initiate memory mapping. |
1391 | * NOTE: The user's request is ignored. For now the buffers are fixed. | 1392 | * NOTE: The user's request is ignored. For now the buffers are fixed. |
1392 | * | 1393 | * |
1393 | *****************************************************************************/ | 1394 | *****************************************************************************/ |
1394 | 1395 | ||
1395 | static int ioctl_reqbufs(void *arg,struct camera_data *cam) | 1396 | static int ioctl_reqbufs(void *arg,struct camera_data *cam) |
1396 | { | 1397 | { |
1397 | struct v4l2_requestbuffers *req = arg; | 1398 | struct v4l2_requestbuffers *req = arg; |
1398 | 1399 | ||
1399 | if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 1400 | if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
1400 | req->memory != V4L2_MEMORY_MMAP) | 1401 | req->memory != V4L2_MEMORY_MMAP) |
1401 | return -EINVAL; | 1402 | return -EINVAL; |
1402 | 1403 | ||
1403 | DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); | 1404 | DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); |
1404 | req->count = cam->num_frames; | 1405 | req->count = cam->num_frames; |
1405 | memset(&req->reserved, 0, sizeof(req->reserved)); | 1406 | memset(&req->reserved, 0, sizeof(req->reserved)); |
1406 | 1407 | ||
1407 | return 0; | 1408 | return 0; |
1408 | } | 1409 | } |
1409 | 1410 | ||
1410 | /****************************************************************************** | 1411 | /****************************************************************************** |
1411 | * | 1412 | * |
1412 | * ioctl_querybuf | 1413 | * ioctl_querybuf |
1413 | * | 1414 | * |
1414 | * V4L2 Query memory buffer status. | 1415 | * V4L2 Query memory buffer status. |
1415 | * | 1416 | * |
1416 | *****************************************************************************/ | 1417 | *****************************************************************************/ |
1417 | 1418 | ||
1418 | static int ioctl_querybuf(void *arg,struct camera_data *cam) | 1419 | static int ioctl_querybuf(void *arg,struct camera_data *cam) |
1419 | { | 1420 | { |
1420 | struct v4l2_buffer *buf = arg; | 1421 | struct v4l2_buffer *buf = arg; |
1421 | 1422 | ||
1422 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 1423 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
1423 | buf->index > cam->num_frames) | 1424 | buf->index > cam->num_frames) |
1424 | return -EINVAL; | 1425 | return -EINVAL; |
1425 | 1426 | ||
1426 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | 1427 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; |
1427 | buf->length = cam->frame_size; | 1428 | buf->length = cam->frame_size; |
1428 | 1429 | ||
1429 | buf->memory = V4L2_MEMORY_MMAP; | 1430 | buf->memory = V4L2_MEMORY_MMAP; |
1430 | 1431 | ||
1431 | if(cam->mmapped) | 1432 | if(cam->mmapped) |
1432 | buf->flags = V4L2_BUF_FLAG_MAPPED; | 1433 | buf->flags = V4L2_BUF_FLAG_MAPPED; |
1433 | else | 1434 | else |
1434 | buf->flags = 0; | 1435 | buf->flags = 0; |
1435 | 1436 | ||
1436 | switch (cam->buffers[buf->index].status) { | 1437 | switch (cam->buffers[buf->index].status) { |
1437 | case FRAME_EMPTY: | 1438 | case FRAME_EMPTY: |
1438 | case FRAME_ERROR: | 1439 | case FRAME_ERROR: |
1439 | case FRAME_READING: | 1440 | case FRAME_READING: |
1440 | buf->bytesused = 0; | 1441 | buf->bytesused = 0; |
1441 | buf->flags = V4L2_BUF_FLAG_QUEUED; | 1442 | buf->flags = V4L2_BUF_FLAG_QUEUED; |
1442 | break; | 1443 | break; |
1443 | case FRAME_READY: | 1444 | case FRAME_READY: |
1444 | buf->bytesused = cam->buffers[buf->index].length; | 1445 | buf->bytesused = cam->buffers[buf->index].length; |
1445 | buf->timestamp = cam->buffers[buf->index].timestamp; | 1446 | buf->timestamp = cam->buffers[buf->index].timestamp; |
1446 | buf->sequence = cam->buffers[buf->index].seq; | 1447 | buf->sequence = cam->buffers[buf->index].seq; |
1447 | buf->flags = V4L2_BUF_FLAG_DONE; | 1448 | buf->flags = V4L2_BUF_FLAG_DONE; |
1448 | break; | 1449 | break; |
1449 | } | 1450 | } |
1450 | 1451 | ||
1451 | DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", | 1452 | DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", |
1452 | buf->index, buf->m.offset, buf->flags, buf->sequence, | 1453 | buf->index, buf->m.offset, buf->flags, buf->sequence, |
1453 | buf->bytesused); | 1454 | buf->bytesused); |
1454 | 1455 | ||
1455 | return 0; | 1456 | return 0; |
1456 | } | 1457 | } |
1457 | 1458 | ||
1458 | /****************************************************************************** | 1459 | /****************************************************************************** |
1459 | * | 1460 | * |
1460 | * ioctl_qbuf | 1461 | * ioctl_qbuf |
1461 | * | 1462 | * |
1462 | * V4L2 User is freeing buffer | 1463 | * V4L2 User is freeing buffer |
1463 | * | 1464 | * |
1464 | *****************************************************************************/ | 1465 | *****************************************************************************/ |
1465 | 1466 | ||
1466 | static int ioctl_qbuf(void *arg,struct camera_data *cam) | 1467 | static int ioctl_qbuf(void *arg,struct camera_data *cam) |
1467 | { | 1468 | { |
1468 | struct v4l2_buffer *buf = arg; | 1469 | struct v4l2_buffer *buf = arg; |
1469 | 1470 | ||
1470 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 1471 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
1471 | buf->memory != V4L2_MEMORY_MMAP || | 1472 | buf->memory != V4L2_MEMORY_MMAP || |
1472 | buf->index > cam->num_frames) | 1473 | buf->index > cam->num_frames) |
1473 | return -EINVAL; | 1474 | return -EINVAL; |
1474 | 1475 | ||
1475 | DBG("QBUF #%d\n", buf->index); | 1476 | DBG("QBUF #%d\n", buf->index); |
1476 | 1477 | ||
1477 | if(cam->buffers[buf->index].status == FRAME_READY) | 1478 | if(cam->buffers[buf->index].status == FRAME_READY) |
1478 | cam->buffers[buf->index].status = FRAME_EMPTY; | 1479 | cam->buffers[buf->index].status = FRAME_EMPTY; |
1479 | 1480 | ||
1480 | return 0; | 1481 | return 0; |
1481 | } | 1482 | } |
1482 | 1483 | ||
1483 | /****************************************************************************** | 1484 | /****************************************************************************** |
1484 | * | 1485 | * |
1485 | * find_earliest_filled_buffer | 1486 | * find_earliest_filled_buffer |
1486 | * | 1487 | * |
1487 | * Helper for ioctl_dqbuf. Find the next ready buffer. | 1488 | * Helper for ioctl_dqbuf. Find the next ready buffer. |
1488 | * | 1489 | * |
1489 | *****************************************************************************/ | 1490 | *****************************************************************************/ |
1490 | 1491 | ||
1491 | static int find_earliest_filled_buffer(struct camera_data *cam) | 1492 | static int find_earliest_filled_buffer(struct camera_data *cam) |
1492 | { | 1493 | { |
1493 | int i; | 1494 | int i; |
1494 | int found = -1; | 1495 | int found = -1; |
1495 | for (i=0; i<cam->num_frames; i++) { | 1496 | for (i=0; i<cam->num_frames; i++) { |
1496 | if(cam->buffers[i].status == FRAME_READY) { | 1497 | if(cam->buffers[i].status == FRAME_READY) { |
1497 | if(found < 0) { | 1498 | if(found < 0) { |
1498 | found = i; | 1499 | found = i; |
1499 | } else { | 1500 | } else { |
1500 | /* find which buffer is earlier */ | 1501 | /* find which buffer is earlier */ |
1501 | struct timeval *tv1, *tv2; | 1502 | struct timeval *tv1, *tv2; |
1502 | tv1 = &cam->buffers[i].timestamp; | 1503 | tv1 = &cam->buffers[i].timestamp; |
1503 | tv2 = &cam->buffers[found].timestamp; | 1504 | tv2 = &cam->buffers[found].timestamp; |
1504 | if(tv1->tv_sec < tv2->tv_sec || | 1505 | if(tv1->tv_sec < tv2->tv_sec || |
1505 | (tv1->tv_sec == tv2->tv_sec && | 1506 | (tv1->tv_sec == tv2->tv_sec && |
1506 | tv1->tv_usec < tv2->tv_usec)) | 1507 | tv1->tv_usec < tv2->tv_usec)) |
1507 | found = i; | 1508 | found = i; |
1508 | } | 1509 | } |
1509 | } | 1510 | } |
1510 | } | 1511 | } |
1511 | return found; | 1512 | return found; |
1512 | } | 1513 | } |
1513 | 1514 | ||
1514 | /****************************************************************************** | 1515 | /****************************************************************************** |
1515 | * | 1516 | * |
1516 | * ioctl_dqbuf | 1517 | * ioctl_dqbuf |
1517 | * | 1518 | * |
1518 | * V4L2 User is asking for a filled buffer. | 1519 | * V4L2 User is asking for a filled buffer. |
1519 | * | 1520 | * |
1520 | *****************************************************************************/ | 1521 | *****************************************************************************/ |
1521 | 1522 | ||
1522 | static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) | 1523 | static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) |
1523 | { | 1524 | { |
1524 | struct v4l2_buffer *buf = arg; | 1525 | struct v4l2_buffer *buf = arg; |
1525 | int frame; | 1526 | int frame; |
1526 | 1527 | ||
1527 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 1528 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
1528 | buf->memory != V4L2_MEMORY_MMAP) | 1529 | buf->memory != V4L2_MEMORY_MMAP) |
1529 | return -EINVAL; | 1530 | return -EINVAL; |
1530 | 1531 | ||
1531 | frame = find_earliest_filled_buffer(cam); | 1532 | frame = find_earliest_filled_buffer(cam); |
1532 | 1533 | ||
1533 | if(frame < 0 && file->f_flags&O_NONBLOCK) | 1534 | if(frame < 0 && file->f_flags&O_NONBLOCK) |
1534 | return -EAGAIN; | 1535 | return -EAGAIN; |
1535 | 1536 | ||
1536 | if(frame < 0) { | 1537 | if(frame < 0) { |
1537 | /* Wait for a frame to become available */ | 1538 | /* Wait for a frame to become available */ |
1538 | struct framebuf *cb=cam->curbuff; | 1539 | struct framebuf *cb=cam->curbuff; |
1539 | mutex_unlock(&cam->busy_lock); | 1540 | mutex_unlock(&cam->busy_lock); |
1540 | wait_event_interruptible(cam->wq_stream, | 1541 | wait_event_interruptible(cam->wq_stream, |
1541 | !cam->present || | 1542 | !cam->present || |
1542 | (cb=cam->curbuff)->status == FRAME_READY); | 1543 | (cb=cam->curbuff)->status == FRAME_READY); |
1543 | mutex_lock(&cam->busy_lock); | 1544 | mutex_lock(&cam->busy_lock); |
1544 | if (signal_pending(current)) | 1545 | if (signal_pending(current)) |
1545 | return -ERESTARTSYS; | 1546 | return -ERESTARTSYS; |
1546 | if(!cam->present) | 1547 | if(!cam->present) |
1547 | return -ENOTTY; | 1548 | return -ENOTTY; |
1548 | frame = cb->num; | 1549 | frame = cb->num; |
1549 | } | 1550 | } |
1550 | 1551 | ||
1551 | 1552 | ||
1552 | buf->index = frame; | 1553 | buf->index = frame; |
1553 | buf->bytesused = cam->buffers[buf->index].length; | 1554 | buf->bytesused = cam->buffers[buf->index].length; |
1554 | buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; | 1555 | buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; |
1555 | buf->field = V4L2_FIELD_NONE; | 1556 | buf->field = V4L2_FIELD_NONE; |
1556 | buf->timestamp = cam->buffers[buf->index].timestamp; | 1557 | buf->timestamp = cam->buffers[buf->index].timestamp; |
1557 | buf->sequence = cam->buffers[buf->index].seq; | 1558 | buf->sequence = cam->buffers[buf->index].seq; |
1558 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | 1559 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; |
1559 | buf->length = cam->frame_size; | 1560 | buf->length = cam->frame_size; |
1560 | buf->input = 0; | 1561 | buf->input = 0; |
1561 | buf->reserved = 0; | 1562 | buf->reserved = 0; |
1562 | memset(&buf->timecode, 0, sizeof(buf->timecode)); | 1563 | memset(&buf->timecode, 0, sizeof(buf->timecode)); |
1563 | 1564 | ||
1564 | DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, | 1565 | DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, |
1565 | cam->buffers[buf->index].status, buf->sequence, buf->bytesused); | 1566 | cam->buffers[buf->index].status, buf->sequence, buf->bytesused); |
1566 | 1567 | ||
1567 | return 0; | 1568 | return 0; |
1568 | } | 1569 | } |
1569 | 1570 | ||
1570 | /****************************************************************************** | 1571 | /****************************************************************************** |
1571 | * | 1572 | * |
1572 | * cpia2_ioctl | 1573 | * cpia2_ioctl |
1573 | * | 1574 | * |
1574 | *****************************************************************************/ | 1575 | *****************************************************************************/ |
1575 | static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 1576 | static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) |
1576 | { | 1577 | { |
1577 | struct camera_data *cam = video_drvdata(file); | 1578 | struct camera_data *cam = video_drvdata(file); |
1578 | long retval = 0; | 1579 | long retval = 0; |
1579 | 1580 | ||
1580 | if (!cam) | 1581 | if (!cam) |
1581 | return -ENOTTY; | 1582 | return -ENOTTY; |
1582 | 1583 | ||
1583 | /* make this _really_ smp-safe */ | 1584 | /* make this _really_ smp-safe */ |
1584 | if (mutex_lock_interruptible(&cam->busy_lock)) | 1585 | if (mutex_lock_interruptible(&cam->busy_lock)) |
1585 | return -ERESTARTSYS; | 1586 | return -ERESTARTSYS; |
1586 | 1587 | ||
1587 | if (!cam->present) { | 1588 | if (!cam->present) { |
1588 | mutex_unlock(&cam->busy_lock); | 1589 | mutex_unlock(&cam->busy_lock); |
1589 | return -ENODEV; | 1590 | return -ENODEV; |
1590 | } | 1591 | } |
1591 | 1592 | ||
1592 | /* Priority check */ | 1593 | /* Priority check */ |
1593 | switch (cmd) { | 1594 | switch (cmd) { |
1594 | case VIDIOCSWIN: | 1595 | case VIDIOCSWIN: |
1595 | case VIDIOCMCAPTURE: | 1596 | case VIDIOCMCAPTURE: |
1596 | case VIDIOC_S_FMT: | 1597 | case VIDIOC_S_FMT: |
1597 | { | 1598 | { |
1598 | struct cpia2_fh *fh = file->private_data; | 1599 | struct cpia2_fh *fh = file->private_data; |
1599 | retval = v4l2_prio_check(&cam->prio, &fh->prio); | 1600 | retval = v4l2_prio_check(&cam->prio, &fh->prio); |
1600 | if(retval) { | 1601 | if(retval) { |
1601 | mutex_unlock(&cam->busy_lock); | 1602 | mutex_unlock(&cam->busy_lock); |
1602 | return retval; | 1603 | return retval; |
1603 | } | 1604 | } |
1604 | break; | 1605 | break; |
1605 | } | 1606 | } |
1606 | case VIDIOCGMBUF: | 1607 | case VIDIOCGMBUF: |
1607 | case VIDIOCSYNC: | 1608 | case VIDIOCSYNC: |
1608 | { | 1609 | { |
1609 | struct cpia2_fh *fh = file->private_data; | 1610 | struct cpia2_fh *fh = file->private_data; |
1610 | if(fh->prio != V4L2_PRIORITY_RECORD) { | 1611 | if(fh->prio != V4L2_PRIORITY_RECORD) { |
1611 | mutex_unlock(&cam->busy_lock); | 1612 | mutex_unlock(&cam->busy_lock); |
1612 | return -EBUSY; | 1613 | return -EBUSY; |
1613 | } | 1614 | } |
1614 | break; | 1615 | break; |
1615 | } | 1616 | } |
1616 | default: | 1617 | default: |
1617 | break; | 1618 | break; |
1618 | } | 1619 | } |
1619 | 1620 | ||
1620 | switch (cmd) { | 1621 | switch (cmd) { |
1621 | case VIDIOCGCAP: /* query capabilities */ | 1622 | case VIDIOCGCAP: /* query capabilities */ |
1622 | retval = ioctl_cap_query(arg, cam); | 1623 | retval = ioctl_cap_query(arg, cam); |
1623 | break; | 1624 | break; |
1624 | 1625 | ||
1625 | case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */ | 1626 | case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */ |
1626 | retval = ioctl_get_channel(arg); | 1627 | retval = ioctl_get_channel(arg); |
1627 | break; | 1628 | break; |
1628 | case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */ | 1629 | case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */ |
1629 | retval = ioctl_set_channel(arg); | 1630 | retval = ioctl_set_channel(arg); |
1630 | break; | 1631 | break; |
1631 | case VIDIOCGPICT: /* image properties */ | 1632 | case VIDIOCGPICT: /* image properties */ |
1632 | memcpy(arg, &cam->vp, sizeof(struct video_picture)); | 1633 | memcpy(arg, &cam->vp, sizeof(struct video_picture)); |
1633 | break; | 1634 | break; |
1634 | case VIDIOCSPICT: | 1635 | case VIDIOCSPICT: |
1635 | retval = ioctl_set_image_prop(arg, cam); | 1636 | retval = ioctl_set_image_prop(arg, cam); |
1636 | break; | 1637 | break; |
1637 | case VIDIOCGWIN: /* get/set capture window */ | 1638 | case VIDIOCGWIN: /* get/set capture window */ |
1638 | memcpy(arg, &cam->vw, sizeof(struct video_window)); | 1639 | memcpy(arg, &cam->vw, sizeof(struct video_window)); |
1639 | break; | 1640 | break; |
1640 | case VIDIOCSWIN: | 1641 | case VIDIOCSWIN: |
1641 | retval = ioctl_set_window_size(arg, cam, file->private_data); | 1642 | retval = ioctl_set_window_size(arg, cam, file->private_data); |
1642 | break; | 1643 | break; |
1643 | case VIDIOCGMBUF: /* mmap interface */ | 1644 | case VIDIOCGMBUF: /* mmap interface */ |
1644 | retval = ioctl_get_mbuf(arg, cam); | 1645 | retval = ioctl_get_mbuf(arg, cam); |
1645 | break; | 1646 | break; |
1646 | case VIDIOCMCAPTURE: | 1647 | case VIDIOCMCAPTURE: |
1647 | retval = ioctl_mcapture(arg, cam, file->private_data); | 1648 | retval = ioctl_mcapture(arg, cam, file->private_data); |
1648 | break; | 1649 | break; |
1649 | case VIDIOCSYNC: | 1650 | case VIDIOCSYNC: |
1650 | retval = ioctl_sync(arg, cam); | 1651 | retval = ioctl_sync(arg, cam); |
1651 | break; | 1652 | break; |
1652 | /* pointless to implement overlay with this camera */ | 1653 | /* pointless to implement overlay with this camera */ |
1653 | case VIDIOCCAPTURE: | 1654 | case VIDIOCCAPTURE: |
1654 | case VIDIOCGFBUF: | 1655 | case VIDIOCGFBUF: |
1655 | case VIDIOCSFBUF: | 1656 | case VIDIOCSFBUF: |
1656 | case VIDIOCKEY: | 1657 | case VIDIOCKEY: |
1657 | retval = -EINVAL; | 1658 | retval = -EINVAL; |
1658 | break; | 1659 | break; |
1659 | 1660 | ||
1660 | /* tuner interface - we have none */ | 1661 | /* tuner interface - we have none */ |
1661 | case VIDIOCGTUNER: | 1662 | case VIDIOCGTUNER: |
1662 | case VIDIOCSTUNER: | 1663 | case VIDIOCSTUNER: |
1663 | case VIDIOCGFREQ: | 1664 | case VIDIOCGFREQ: |
1664 | case VIDIOCSFREQ: | 1665 | case VIDIOCSFREQ: |
1665 | retval = -EINVAL; | 1666 | retval = -EINVAL; |
1666 | break; | 1667 | break; |
1667 | 1668 | ||
1668 | /* audio interface - we have none */ | 1669 | /* audio interface - we have none */ |
1669 | case VIDIOCGAUDIO: | 1670 | case VIDIOCGAUDIO: |
1670 | case VIDIOCSAUDIO: | 1671 | case VIDIOCSAUDIO: |
1671 | retval = -EINVAL; | 1672 | retval = -EINVAL; |
1672 | break; | 1673 | break; |
1673 | 1674 | ||
1674 | /* CPIA2 extension to Video4Linux API */ | 1675 | /* CPIA2 extension to Video4Linux API */ |
1675 | case CPIA2_IOC_SET_GPIO: | 1676 | case CPIA2_IOC_SET_GPIO: |
1676 | retval = ioctl_set_gpio(arg, cam); | 1677 | retval = ioctl_set_gpio(arg, cam); |
1677 | break; | 1678 | break; |
1678 | case VIDIOC_QUERYCAP: | 1679 | case VIDIOC_QUERYCAP: |
1679 | retval = ioctl_querycap(arg,cam); | 1680 | retval = ioctl_querycap(arg,cam); |
1680 | break; | 1681 | break; |
1681 | 1682 | ||
1682 | case VIDIOC_ENUMINPUT: | 1683 | case VIDIOC_ENUMINPUT: |
1683 | case VIDIOC_G_INPUT: | 1684 | case VIDIOC_G_INPUT: |
1684 | case VIDIOC_S_INPUT: | 1685 | case VIDIOC_S_INPUT: |
1685 | retval = ioctl_input(cmd, arg, cam); | 1686 | retval = ioctl_input(cmd, arg, cam); |
1686 | break; | 1687 | break; |
1687 | 1688 | ||
1688 | case VIDIOC_ENUM_FMT: | 1689 | case VIDIOC_ENUM_FMT: |
1689 | retval = ioctl_enum_fmt(arg,cam); | 1690 | retval = ioctl_enum_fmt(arg,cam); |
1690 | break; | 1691 | break; |
1691 | case VIDIOC_TRY_FMT: | 1692 | case VIDIOC_TRY_FMT: |
1692 | retval = ioctl_try_fmt(arg,cam); | 1693 | retval = ioctl_try_fmt(arg,cam); |
1693 | break; | 1694 | break; |
1694 | case VIDIOC_G_FMT: | 1695 | case VIDIOC_G_FMT: |
1695 | retval = ioctl_get_fmt(arg,cam); | 1696 | retval = ioctl_get_fmt(arg,cam); |
1696 | break; | 1697 | break; |
1697 | case VIDIOC_S_FMT: | 1698 | case VIDIOC_S_FMT: |
1698 | retval = ioctl_set_fmt(arg,cam,file->private_data); | 1699 | retval = ioctl_set_fmt(arg,cam,file->private_data); |
1699 | break; | 1700 | break; |
1700 | 1701 | ||
1701 | case VIDIOC_CROPCAP: | 1702 | case VIDIOC_CROPCAP: |
1702 | retval = ioctl_cropcap(arg,cam); | 1703 | retval = ioctl_cropcap(arg,cam); |
1703 | break; | 1704 | break; |
1704 | case VIDIOC_G_CROP: | 1705 | case VIDIOC_G_CROP: |
1705 | case VIDIOC_S_CROP: | 1706 | case VIDIOC_S_CROP: |
1706 | // TODO: I think cropping can be implemented - SJB | 1707 | // TODO: I think cropping can be implemented - SJB |
1707 | retval = -EINVAL; | 1708 | retval = -EINVAL; |
1708 | break; | 1709 | break; |
1709 | 1710 | ||
1710 | case VIDIOC_QUERYCTRL: | 1711 | case VIDIOC_QUERYCTRL: |
1711 | retval = ioctl_queryctrl(arg,cam); | 1712 | retval = ioctl_queryctrl(arg,cam); |
1712 | break; | 1713 | break; |
1713 | case VIDIOC_QUERYMENU: | 1714 | case VIDIOC_QUERYMENU: |
1714 | retval = ioctl_querymenu(arg,cam); | 1715 | retval = ioctl_querymenu(arg,cam); |
1715 | break; | 1716 | break; |
1716 | case VIDIOC_G_CTRL: | 1717 | case VIDIOC_G_CTRL: |
1717 | retval = ioctl_g_ctrl(arg,cam); | 1718 | retval = ioctl_g_ctrl(arg,cam); |
1718 | break; | 1719 | break; |
1719 | case VIDIOC_S_CTRL: | 1720 | case VIDIOC_S_CTRL: |
1720 | retval = ioctl_s_ctrl(arg,cam); | 1721 | retval = ioctl_s_ctrl(arg,cam); |
1721 | break; | 1722 | break; |
1722 | 1723 | ||
1723 | case VIDIOC_G_JPEGCOMP: | 1724 | case VIDIOC_G_JPEGCOMP: |
1724 | retval = ioctl_g_jpegcomp(arg,cam); | 1725 | retval = ioctl_g_jpegcomp(arg,cam); |
1725 | break; | 1726 | break; |
1726 | case VIDIOC_S_JPEGCOMP: | 1727 | case VIDIOC_S_JPEGCOMP: |
1727 | retval = ioctl_s_jpegcomp(arg,cam); | 1728 | retval = ioctl_s_jpegcomp(arg,cam); |
1728 | break; | 1729 | break; |
1729 | 1730 | ||
1730 | case VIDIOC_G_PRIORITY: | 1731 | case VIDIOC_G_PRIORITY: |
1731 | { | 1732 | { |
1732 | struct cpia2_fh *fh = file->private_data; | 1733 | struct cpia2_fh *fh = file->private_data; |
1733 | *(enum v4l2_priority*)arg = fh->prio; | 1734 | *(enum v4l2_priority*)arg = fh->prio; |
1734 | break; | 1735 | break; |
1735 | } | 1736 | } |
1736 | case VIDIOC_S_PRIORITY: | 1737 | case VIDIOC_S_PRIORITY: |
1737 | { | 1738 | { |
1738 | struct cpia2_fh *fh = file->private_data; | 1739 | struct cpia2_fh *fh = file->private_data; |
1739 | enum v4l2_priority prio; | 1740 | enum v4l2_priority prio; |
1740 | prio = *(enum v4l2_priority*)arg; | 1741 | prio = *(enum v4l2_priority*)arg; |
1741 | if(cam->streaming && | 1742 | if(cam->streaming && |
1742 | prio != fh->prio && | 1743 | prio != fh->prio && |
1743 | fh->prio == V4L2_PRIORITY_RECORD) { | 1744 | fh->prio == V4L2_PRIORITY_RECORD) { |
1744 | /* Can't drop record priority while streaming */ | 1745 | /* Can't drop record priority while streaming */ |
1745 | retval = -EBUSY; | 1746 | retval = -EBUSY; |
1746 | } else if(prio == V4L2_PRIORITY_RECORD && | 1747 | } else if(prio == V4L2_PRIORITY_RECORD && |
1747 | prio != fh->prio && | 1748 | prio != fh->prio && |
1748 | v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) { | 1749 | v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) { |
1749 | /* Only one program can record at a time */ | 1750 | /* Only one program can record at a time */ |
1750 | retval = -EBUSY; | 1751 | retval = -EBUSY; |
1751 | } else { | 1752 | } else { |
1752 | retval = v4l2_prio_change(&cam->prio, &fh->prio, prio); | 1753 | retval = v4l2_prio_change(&cam->prio, &fh->prio, prio); |
1753 | } | 1754 | } |
1754 | break; | 1755 | break; |
1755 | } | 1756 | } |
1756 | 1757 | ||
1757 | case VIDIOC_REQBUFS: | 1758 | case VIDIOC_REQBUFS: |
1758 | retval = ioctl_reqbufs(arg,cam); | 1759 | retval = ioctl_reqbufs(arg,cam); |
1759 | break; | 1760 | break; |
1760 | case VIDIOC_QUERYBUF: | 1761 | case VIDIOC_QUERYBUF: |
1761 | retval = ioctl_querybuf(arg,cam); | 1762 | retval = ioctl_querybuf(arg,cam); |
1762 | break; | 1763 | break; |
1763 | case VIDIOC_QBUF: | 1764 | case VIDIOC_QBUF: |
1764 | retval = ioctl_qbuf(arg,cam); | 1765 | retval = ioctl_qbuf(arg,cam); |
1765 | break; | 1766 | break; |
1766 | case VIDIOC_DQBUF: | 1767 | case VIDIOC_DQBUF: |
1767 | retval = ioctl_dqbuf(arg,cam,file); | 1768 | retval = ioctl_dqbuf(arg,cam,file); |
1768 | break; | 1769 | break; |
1769 | case VIDIOC_STREAMON: | 1770 | case VIDIOC_STREAMON: |
1770 | { | 1771 | { |
1771 | int type; | 1772 | int type; |
1772 | DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); | 1773 | DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); |
1773 | type = *(int*)arg; | 1774 | type = *(int*)arg; |
1774 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1775 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1775 | retval = -EINVAL; | 1776 | retval = -EINVAL; |
1776 | 1777 | ||
1777 | if(!cam->streaming) { | 1778 | if(!cam->streaming) { |
1778 | retval = cpia2_usb_stream_start(cam, | 1779 | retval = cpia2_usb_stream_start(cam, |
1779 | cam->params.camera_state.stream_mode); | 1780 | cam->params.camera_state.stream_mode); |
1780 | } else { | 1781 | } else { |
1781 | retval = -EINVAL; | 1782 | retval = -EINVAL; |
1782 | } | 1783 | } |
1783 | 1784 | ||
1784 | break; | 1785 | break; |
1785 | } | 1786 | } |
1786 | case VIDIOC_STREAMOFF: | 1787 | case VIDIOC_STREAMOFF: |
1787 | { | 1788 | { |
1788 | int type; | 1789 | int type; |
1789 | DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); | 1790 | DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); |
1790 | type = *(int*)arg; | 1791 | type = *(int*)arg; |
1791 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1792 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1792 | retval = -EINVAL; | 1793 | retval = -EINVAL; |
1793 | 1794 | ||
1794 | if(cam->streaming) { | 1795 | if(cam->streaming) { |
1795 | retval = cpia2_usb_stream_stop(cam); | 1796 | retval = cpia2_usb_stream_stop(cam); |
1796 | } else { | 1797 | } else { |
1797 | retval = -EINVAL; | 1798 | retval = -EINVAL; |
1798 | } | 1799 | } |
1799 | 1800 | ||
1800 | break; | 1801 | break; |
1801 | } | 1802 | } |
1802 | 1803 | ||
1803 | case VIDIOC_ENUMOUTPUT: | 1804 | case VIDIOC_ENUMOUTPUT: |
1804 | case VIDIOC_G_OUTPUT: | 1805 | case VIDIOC_G_OUTPUT: |
1805 | case VIDIOC_S_OUTPUT: | 1806 | case VIDIOC_S_OUTPUT: |
1806 | case VIDIOC_G_MODULATOR: | 1807 | case VIDIOC_G_MODULATOR: |
1807 | case VIDIOC_S_MODULATOR: | 1808 | case VIDIOC_S_MODULATOR: |
1808 | 1809 | ||
1809 | case VIDIOC_ENUMAUDIO: | 1810 | case VIDIOC_ENUMAUDIO: |
1810 | case VIDIOC_G_AUDIO: | 1811 | case VIDIOC_G_AUDIO: |
1811 | case VIDIOC_S_AUDIO: | 1812 | case VIDIOC_S_AUDIO: |
1812 | 1813 | ||
1813 | case VIDIOC_ENUMAUDOUT: | 1814 | case VIDIOC_ENUMAUDOUT: |
1814 | case VIDIOC_G_AUDOUT: | 1815 | case VIDIOC_G_AUDOUT: |
1815 | case VIDIOC_S_AUDOUT: | 1816 | case VIDIOC_S_AUDOUT: |
1816 | 1817 | ||
1817 | case VIDIOC_ENUMSTD: | 1818 | case VIDIOC_ENUMSTD: |
1818 | case VIDIOC_QUERYSTD: | 1819 | case VIDIOC_QUERYSTD: |
1819 | case VIDIOC_G_STD: | 1820 | case VIDIOC_G_STD: |
1820 | case VIDIOC_S_STD: | 1821 | case VIDIOC_S_STD: |
1821 | 1822 | ||
1822 | case VIDIOC_G_TUNER: | 1823 | case VIDIOC_G_TUNER: |
1823 | case VIDIOC_S_TUNER: | 1824 | case VIDIOC_S_TUNER: |
1824 | case VIDIOC_G_FREQUENCY: | 1825 | case VIDIOC_G_FREQUENCY: |
1825 | case VIDIOC_S_FREQUENCY: | 1826 | case VIDIOC_S_FREQUENCY: |
1826 | 1827 | ||
1827 | case VIDIOC_OVERLAY: | 1828 | case VIDIOC_OVERLAY: |
1828 | case VIDIOC_G_FBUF: | 1829 | case VIDIOC_G_FBUF: |
1829 | case VIDIOC_S_FBUF: | 1830 | case VIDIOC_S_FBUF: |
1830 | 1831 | ||
1831 | case VIDIOC_G_PARM: | 1832 | case VIDIOC_G_PARM: |
1832 | case VIDIOC_S_PARM: | 1833 | case VIDIOC_S_PARM: |
1833 | retval = -EINVAL; | 1834 | retval = -EINVAL; |
1834 | break; | 1835 | break; |
1835 | default: | 1836 | default: |
1836 | retval = -ENOIOCTLCMD; | 1837 | retval = -ENOIOCTLCMD; |
1837 | break; | 1838 | break; |
1838 | } | 1839 | } |
1839 | 1840 | ||
1840 | mutex_unlock(&cam->busy_lock); | 1841 | mutex_unlock(&cam->busy_lock); |
1841 | return retval; | 1842 | return retval; |
1842 | } | 1843 | } |
1843 | 1844 | ||
1844 | static long cpia2_ioctl(struct file *file, | 1845 | static long cpia2_ioctl(struct file *file, |
1845 | unsigned int cmd, unsigned long arg) | 1846 | unsigned int cmd, unsigned long arg) |
1846 | { | 1847 | { |
1847 | return video_usercopy(file, cmd, arg, cpia2_do_ioctl); | 1848 | return video_usercopy(file, cmd, arg, cpia2_do_ioctl); |
1848 | } | 1849 | } |
1849 | 1850 | ||
1850 | /****************************************************************************** | 1851 | /****************************************************************************** |
1851 | * | 1852 | * |
1852 | * cpia2_mmap | 1853 | * cpia2_mmap |
1853 | * | 1854 | * |
1854 | *****************************************************************************/ | 1855 | *****************************************************************************/ |
1855 | static int cpia2_mmap(struct file *file, struct vm_area_struct *area) | 1856 | static int cpia2_mmap(struct file *file, struct vm_area_struct *area) |
1856 | { | 1857 | { |
1857 | struct camera_data *cam = video_drvdata(file); | 1858 | struct camera_data *cam = video_drvdata(file); |
1858 | int retval; | 1859 | int retval; |
1859 | 1860 | ||
1860 | /* Priority check */ | 1861 | /* Priority check */ |
1861 | struct cpia2_fh *fh = file->private_data; | 1862 | struct cpia2_fh *fh = file->private_data; |
1862 | if(fh->prio != V4L2_PRIORITY_RECORD) { | 1863 | if(fh->prio != V4L2_PRIORITY_RECORD) { |
1863 | return -EBUSY; | 1864 | return -EBUSY; |
1864 | } | 1865 | } |
1865 | 1866 | ||
1866 | retval = cpia2_remap_buffer(cam, area); | 1867 | retval = cpia2_remap_buffer(cam, area); |
1867 | 1868 | ||
1868 | if(!retval) | 1869 | if(!retval) |
1869 | fh->mmapped = 1; | 1870 | fh->mmapped = 1; |
1870 | return retval; | 1871 | return retval; |
1871 | } | 1872 | } |
1872 | 1873 | ||
1873 | /****************************************************************************** | 1874 | /****************************************************************************** |
1874 | * | 1875 | * |
1875 | * reset_camera_struct_v4l | 1876 | * reset_camera_struct_v4l |
1876 | * | 1877 | * |
1877 | * Sets all values to the defaults | 1878 | * Sets all values to the defaults |
1878 | *****************************************************************************/ | 1879 | *****************************************************************************/ |
1879 | static void reset_camera_struct_v4l(struct camera_data *cam) | 1880 | static void reset_camera_struct_v4l(struct camera_data *cam) |
1880 | { | 1881 | { |
1881 | /*** | 1882 | /*** |
1882 | * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP | 1883 | * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP |
1883 | * Ioctl. Here, just do the window and picture stucts. | 1884 | * Ioctl. Here, just do the window and picture stucts. |
1884 | ***/ | 1885 | ***/ |
1885 | cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */ | 1886 | cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */ |
1886 | cam->vp.brightness = (u16) cam->params.color_params.brightness * 256; | 1887 | cam->vp.brightness = (u16) cam->params.color_params.brightness * 256; |
1887 | cam->vp.colour = (u16) cam->params.color_params.saturation * 256; | 1888 | cam->vp.colour = (u16) cam->params.color_params.saturation * 256; |
1888 | cam->vp.contrast = (u16) cam->params.color_params.contrast * 256; | 1889 | cam->vp.contrast = (u16) cam->params.color_params.contrast * 256; |
1889 | 1890 | ||
1890 | cam->vw.x = 0; | 1891 | cam->vw.x = 0; |
1891 | cam->vw.y = 0; | 1892 | cam->vw.y = 0; |
1892 | cam->vw.width = cam->params.roi.width; | 1893 | cam->vw.width = cam->params.roi.width; |
1893 | cam->vw.height = cam->params.roi.height; | 1894 | cam->vw.height = cam->params.roi.height; |
1894 | cam->vw.flags = 0; | 1895 | cam->vw.flags = 0; |
1895 | cam->vw.clipcount = 0; | 1896 | cam->vw.clipcount = 0; |
1896 | 1897 | ||
1897 | cam->frame_size = buffer_size; | 1898 | cam->frame_size = buffer_size; |
1898 | cam->num_frames = num_buffers; | 1899 | cam->num_frames = num_buffers; |
1899 | 1900 | ||
1900 | /* FlickerModes */ | 1901 | /* FlickerModes */ |
1901 | cam->params.flicker_control.flicker_mode_req = flicker_mode; | 1902 | cam->params.flicker_control.flicker_mode_req = flicker_mode; |
1902 | cam->params.flicker_control.mains_frequency = flicker_freq; | 1903 | cam->params.flicker_control.mains_frequency = flicker_freq; |
1903 | 1904 | ||
1904 | /* streamMode */ | 1905 | /* streamMode */ |
1905 | cam->params.camera_state.stream_mode = alternate; | 1906 | cam->params.camera_state.stream_mode = alternate; |
1906 | 1907 | ||
1907 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | 1908 | cam->pixelformat = V4L2_PIX_FMT_JPEG; |
1908 | v4l2_prio_init(&cam->prio); | 1909 | v4l2_prio_init(&cam->prio); |
1909 | return; | 1910 | return; |
1910 | } | 1911 | } |
1911 | 1912 | ||
1912 | /*** | 1913 | /*** |
1913 | * The v4l video device structure initialized for this device | 1914 | * The v4l video device structure initialized for this device |
1914 | ***/ | 1915 | ***/ |
1915 | static const struct v4l2_file_operations fops_template = { | 1916 | static const struct v4l2_file_operations fops_template = { |
1916 | .owner = THIS_MODULE, | 1917 | .owner = THIS_MODULE, |
1917 | .open = cpia2_open, | 1918 | .open = cpia2_open, |
1918 | .release = cpia2_close, | 1919 | .release = cpia2_close, |
1919 | .read = cpia2_v4l_read, | 1920 | .read = cpia2_v4l_read, |
1920 | .poll = cpia2_v4l_poll, | 1921 | .poll = cpia2_v4l_poll, |
1921 | .ioctl = cpia2_ioctl, | 1922 | .ioctl = cpia2_ioctl, |
1922 | .mmap = cpia2_mmap, | 1923 | .mmap = cpia2_mmap, |
1923 | }; | 1924 | }; |
1924 | 1925 | ||
1925 | static struct video_device cpia2_template = { | 1926 | static struct video_device cpia2_template = { |
1926 | /* I could not find any place for the old .initialize initializer?? */ | 1927 | /* I could not find any place for the old .initialize initializer?? */ |
1927 | .name= "CPiA2 Camera", | 1928 | .name= "CPiA2 Camera", |
1928 | .minor= -1, | 1929 | .minor= -1, |
1929 | .fops= &fops_template, | 1930 | .fops= &fops_template, |
1930 | .release= video_device_release, | 1931 | .release= video_device_release, |
1931 | }; | 1932 | }; |
1932 | 1933 | ||
1933 | /****************************************************************************** | 1934 | /****************************************************************************** |
1934 | * | 1935 | * |
1935 | * cpia2_register_camera | 1936 | * cpia2_register_camera |
1936 | * | 1937 | * |
1937 | *****************************************************************************/ | 1938 | *****************************************************************************/ |
1938 | int cpia2_register_camera(struct camera_data *cam) | 1939 | int cpia2_register_camera(struct camera_data *cam) |
1939 | { | 1940 | { |
1940 | cam->vdev = video_device_alloc(); | 1941 | cam->vdev = video_device_alloc(); |
1941 | if(!cam->vdev) | 1942 | if(!cam->vdev) |
1942 | return -ENOMEM; | 1943 | return -ENOMEM; |
1943 | 1944 | ||
1944 | memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); | 1945 | memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); |
1945 | video_set_drvdata(cam->vdev, cam); | 1946 | video_set_drvdata(cam->vdev, cam); |
1946 | 1947 | ||
1947 | reset_camera_struct_v4l(cam); | 1948 | reset_camera_struct_v4l(cam); |
1948 | 1949 | ||
1949 | /* register v4l device */ | 1950 | /* register v4l device */ |
1950 | if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { | 1951 | if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { |
1951 | ERR("video_register_device failed\n"); | 1952 | ERR("video_register_device failed\n"); |
1952 | video_device_release(cam->vdev); | 1953 | video_device_release(cam->vdev); |
1953 | return -ENODEV; | 1954 | return -ENODEV; |
1954 | } | 1955 | } |
1955 | 1956 | ||
1956 | return 0; | 1957 | return 0; |
1957 | } | 1958 | } |
1958 | 1959 | ||
1959 | /****************************************************************************** | 1960 | /****************************************************************************** |
1960 | * | 1961 | * |
1961 | * cpia2_unregister_camera | 1962 | * cpia2_unregister_camera |
1962 | * | 1963 | * |
1963 | *****************************************************************************/ | 1964 | *****************************************************************************/ |
1964 | void cpia2_unregister_camera(struct camera_data *cam) | 1965 | void cpia2_unregister_camera(struct camera_data *cam) |
1965 | { | 1966 | { |
1966 | if (!cam->open_count) { | 1967 | if (!cam->open_count) { |
1967 | video_unregister_device(cam->vdev); | 1968 | video_unregister_device(cam->vdev); |
1968 | } else { | 1969 | } else { |
1969 | LOG("/dev/video%d removed while open, " | 1970 | LOG("/dev/video%d removed while open, " |
1970 | "deferring video_unregister_device\n", | 1971 | "deferring video_unregister_device\n", |
1971 | cam->vdev->num); | 1972 | cam->vdev->num); |
1972 | } | 1973 | } |
1973 | } | 1974 | } |
1974 | 1975 | ||
1975 | /****************************************************************************** | 1976 | /****************************************************************************** |
1976 | * | 1977 | * |
1977 | * check_parameters | 1978 | * check_parameters |
1978 | * | 1979 | * |
1979 | * Make sure that all user-supplied parameters are sensible | 1980 | * Make sure that all user-supplied parameters are sensible |
1980 | *****************************************************************************/ | 1981 | *****************************************************************************/ |
1981 | static void __init check_parameters(void) | 1982 | static void __init check_parameters(void) |
1982 | { | 1983 | { |
1983 | if(buffer_size < PAGE_SIZE) { | 1984 | if(buffer_size < PAGE_SIZE) { |
1984 | buffer_size = PAGE_SIZE; | 1985 | buffer_size = PAGE_SIZE; |
1985 | LOG("buffer_size too small, setting to %d\n", buffer_size); | 1986 | LOG("buffer_size too small, setting to %d\n", buffer_size); |
1986 | } else if(buffer_size > 1024*1024) { | 1987 | } else if(buffer_size > 1024*1024) { |
1987 | /* arbitrary upper limiit */ | 1988 | /* arbitrary upper limiit */ |
1988 | buffer_size = 1024*1024; | 1989 | buffer_size = 1024*1024; |
1989 | LOG("buffer_size ridiculously large, setting to %d\n", | 1990 | LOG("buffer_size ridiculously large, setting to %d\n", |
1990 | buffer_size); | 1991 | buffer_size); |
1991 | } else { | 1992 | } else { |
1992 | buffer_size += PAGE_SIZE-1; | 1993 | buffer_size += PAGE_SIZE-1; |
1993 | buffer_size &= ~(PAGE_SIZE-1); | 1994 | buffer_size &= ~(PAGE_SIZE-1); |
1994 | } | 1995 | } |
1995 | 1996 | ||
1996 | if(num_buffers < 1) { | 1997 | if(num_buffers < 1) { |
1997 | num_buffers = 1; | 1998 | num_buffers = 1; |
1998 | LOG("num_buffers too small, setting to %d\n", num_buffers); | 1999 | LOG("num_buffers too small, setting to %d\n", num_buffers); |
1999 | } else if(num_buffers > VIDEO_MAX_FRAME) { | 2000 | } else if(num_buffers > VIDEO_MAX_FRAME) { |
2000 | num_buffers = VIDEO_MAX_FRAME; | 2001 | num_buffers = VIDEO_MAX_FRAME; |
2001 | LOG("num_buffers too large, setting to %d\n", num_buffers); | 2002 | LOG("num_buffers too large, setting to %d\n", num_buffers); |
2002 | } | 2003 | } |
2003 | 2004 | ||
2004 | if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { | 2005 | if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { |
2005 | alternate = DEFAULT_ALT; | 2006 | alternate = DEFAULT_ALT; |
2006 | LOG("alternate specified is invalid, using %d\n", alternate); | 2007 | LOG("alternate specified is invalid, using %d\n", alternate); |
2007 | } | 2008 | } |
2008 | 2009 | ||
2009 | if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { | 2010 | if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { |
2010 | flicker_mode = NEVER_FLICKER; | 2011 | flicker_mode = NEVER_FLICKER; |
2011 | LOG("Flicker mode specified is invalid, using %d\n", | 2012 | LOG("Flicker mode specified is invalid, using %d\n", |
2012 | flicker_mode); | 2013 | flicker_mode); |
2013 | } | 2014 | } |
2014 | 2015 | ||
2015 | if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { | 2016 | if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { |
2016 | flicker_freq = FLICKER_60; | 2017 | flicker_freq = FLICKER_60; |
2017 | LOG("Flicker mode specified is invalid, using %d\n", | 2018 | LOG("Flicker mode specified is invalid, using %d\n", |
2018 | flicker_freq); | 2019 | flicker_freq); |
2019 | } | 2020 | } |
2020 | 2021 | ||
2021 | if(video_nr < -1 || video_nr > 64) { | 2022 | if(video_nr < -1 || video_nr > 64) { |
2022 | video_nr = -1; | 2023 | video_nr = -1; |
2023 | LOG("invalid video_nr specified, must be -1 to 64\n"); | 2024 | LOG("invalid video_nr specified, must be -1 to 64\n"); |
2024 | } | 2025 | } |
2025 | 2026 | ||
2026 | DBG("Using %d buffers, each %d bytes, alternate=%d\n", | 2027 | DBG("Using %d buffers, each %d bytes, alternate=%d\n", |
2027 | num_buffers, buffer_size, alternate); | 2028 | num_buffers, buffer_size, alternate); |
2028 | } | 2029 | } |
2029 | 2030 | ||
2030 | /************ Module Stuff ***************/ | 2031 | /************ Module Stuff ***************/ |
2031 | 2032 | ||
2032 | 2033 | ||
2033 | /****************************************************************************** | 2034 | /****************************************************************************** |
2034 | * | 2035 | * |
2035 | * cpia2_init/module_init | 2036 | * cpia2_init/module_init |
2036 | * | 2037 | * |
2037 | *****************************************************************************/ | 2038 | *****************************************************************************/ |
2038 | static int __init cpia2_init(void) | 2039 | static int __init cpia2_init(void) |
2039 | { | 2040 | { |
2040 | LOG("%s v%d.%d.%d\n", | 2041 | LOG("%s v%d.%d.%d\n", |
2041 | ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); | 2042 | ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); |
2042 | check_parameters(); | 2043 | check_parameters(); |
2043 | cpia2_usb_init(); | 2044 | cpia2_usb_init(); |
2044 | return 0; | 2045 | return 0; |
2045 | } | 2046 | } |
2046 | 2047 | ||
2047 | 2048 | ||
2048 | /****************************************************************************** | 2049 | /****************************************************************************** |
2049 | * | 2050 | * |
2050 | * cpia2_exit/module_exit | 2051 | * cpia2_exit/module_exit |
2051 | * | 2052 | * |
2052 | *****************************************************************************/ | 2053 | *****************************************************************************/ |
2053 | static void __exit cpia2_exit(void) | 2054 | static void __exit cpia2_exit(void) |
2054 | { | 2055 | { |
2055 | cpia2_usb_cleanup(); | 2056 | cpia2_usb_cleanup(); |
2056 | schedule_timeout(2 * HZ); | 2057 | schedule_timeout(2 * HZ); |
2057 | } | 2058 | } |
2058 | 2059 | ||
2059 | module_init(cpia2_init); | 2060 | module_init(cpia2_init); |
2060 | module_exit(cpia2_exit); | 2061 | module_exit(cpia2_exit); |
2061 | 2062 | ||
2062 | 2063 |
drivers/media/video/cx23885/cx23885-video.c
1 | /* | 1 | /* |
2 | * Driver for the Conexant CX23885 PCIe bridge | 2 | * Driver for the Conexant CX23885 PCIe bridge |
3 | * | 3 | * |
4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | 4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 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 | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * | 14 | * |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
26 | #include <linux/kmod.h> | 26 | #include <linux/kmod.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/kthread.h> | 31 | #include <linux/kthread.h> |
32 | #include <asm/div64.h> | 32 | #include <asm/div64.h> |
33 | 33 | ||
34 | #include "cx23885.h" | 34 | #include "cx23885.h" |
35 | #include <media/v4l2-common.h> | 35 | #include <media/v4l2-common.h> |
36 | #include <media/v4l2-ioctl.h> | 36 | #include <media/v4l2-ioctl.h> |
37 | 37 | ||
38 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
39 | /* Include V4L1 specific functions. Should be removed soon */ | ||
40 | #include <linux/videodev.h> | ||
41 | #endif | ||
42 | |||
43 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); | 38 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); |
44 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | 39 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); |
45 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
46 | 41 | ||
47 | /* ------------------------------------------------------------------ */ | 42 | /* ------------------------------------------------------------------ */ |
48 | 43 | ||
49 | static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | 44 | static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; |
50 | static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | 45 | static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; |
51 | static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; | 46 | static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; |
52 | 47 | ||
53 | module_param_array(video_nr, int, NULL, 0444); | 48 | module_param_array(video_nr, int, NULL, 0444); |
54 | module_param_array(vbi_nr, int, NULL, 0444); | 49 | module_param_array(vbi_nr, int, NULL, 0444); |
55 | module_param_array(radio_nr, int, NULL, 0444); | 50 | module_param_array(radio_nr, int, NULL, 0444); |
56 | 51 | ||
57 | MODULE_PARM_DESC(video_nr, "video device numbers"); | 52 | MODULE_PARM_DESC(video_nr, "video device numbers"); |
58 | MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); | 53 | MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); |
59 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); | 54 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); |
60 | 55 | ||
61 | static unsigned int video_debug; | 56 | static unsigned int video_debug; |
62 | module_param(video_debug, int, 0644); | 57 | module_param(video_debug, int, 0644); |
63 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | 58 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); |
64 | 59 | ||
65 | static unsigned int irq_debug; | 60 | static unsigned int irq_debug; |
66 | module_param(irq_debug, int, 0644); | 61 | module_param(irq_debug, int, 0644); |
67 | MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); | 62 | MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); |
68 | 63 | ||
69 | static unsigned int vid_limit = 16; | 64 | static unsigned int vid_limit = 16; |
70 | module_param(vid_limit, int, 0644); | 65 | module_param(vid_limit, int, 0644); |
71 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | 66 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); |
72 | 67 | ||
73 | #define dprintk(level, fmt, arg...)\ | 68 | #define dprintk(level, fmt, arg...)\ |
74 | do { if (video_debug >= level)\ | 69 | do { if (video_debug >= level)\ |
75 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ | 70 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ |
76 | } while (0) | 71 | } while (0) |
77 | 72 | ||
78 | /* ------------------------------------------------------------------- */ | 73 | /* ------------------------------------------------------------------- */ |
79 | /* static data */ | 74 | /* static data */ |
80 | 75 | ||
81 | #define FORMAT_FLAGS_PACKED 0x01 | 76 | #define FORMAT_FLAGS_PACKED 0x01 |
82 | 77 | ||
83 | static struct cx23885_fmt formats[] = { | 78 | static struct cx23885_fmt formats[] = { |
84 | { | 79 | { |
85 | .name = "8 bpp, gray", | 80 | .name = "8 bpp, gray", |
86 | .fourcc = V4L2_PIX_FMT_GREY, | 81 | .fourcc = V4L2_PIX_FMT_GREY, |
87 | .depth = 8, | 82 | .depth = 8, |
88 | .flags = FORMAT_FLAGS_PACKED, | 83 | .flags = FORMAT_FLAGS_PACKED, |
89 | }, { | 84 | }, { |
90 | .name = "15 bpp RGB, le", | 85 | .name = "15 bpp RGB, le", |
91 | .fourcc = V4L2_PIX_FMT_RGB555, | 86 | .fourcc = V4L2_PIX_FMT_RGB555, |
92 | .depth = 16, | 87 | .depth = 16, |
93 | .flags = FORMAT_FLAGS_PACKED, | 88 | .flags = FORMAT_FLAGS_PACKED, |
94 | }, { | 89 | }, { |
95 | .name = "15 bpp RGB, be", | 90 | .name = "15 bpp RGB, be", |
96 | .fourcc = V4L2_PIX_FMT_RGB555X, | 91 | .fourcc = V4L2_PIX_FMT_RGB555X, |
97 | .depth = 16, | 92 | .depth = 16, |
98 | .flags = FORMAT_FLAGS_PACKED, | 93 | .flags = FORMAT_FLAGS_PACKED, |
99 | }, { | 94 | }, { |
100 | .name = "16 bpp RGB, le", | 95 | .name = "16 bpp RGB, le", |
101 | .fourcc = V4L2_PIX_FMT_RGB565, | 96 | .fourcc = V4L2_PIX_FMT_RGB565, |
102 | .depth = 16, | 97 | .depth = 16, |
103 | .flags = FORMAT_FLAGS_PACKED, | 98 | .flags = FORMAT_FLAGS_PACKED, |
104 | }, { | 99 | }, { |
105 | .name = "16 bpp RGB, be", | 100 | .name = "16 bpp RGB, be", |
106 | .fourcc = V4L2_PIX_FMT_RGB565X, | 101 | .fourcc = V4L2_PIX_FMT_RGB565X, |
107 | .depth = 16, | 102 | .depth = 16, |
108 | .flags = FORMAT_FLAGS_PACKED, | 103 | .flags = FORMAT_FLAGS_PACKED, |
109 | }, { | 104 | }, { |
110 | .name = "24 bpp RGB, le", | 105 | .name = "24 bpp RGB, le", |
111 | .fourcc = V4L2_PIX_FMT_BGR24, | 106 | .fourcc = V4L2_PIX_FMT_BGR24, |
112 | .depth = 24, | 107 | .depth = 24, |
113 | .flags = FORMAT_FLAGS_PACKED, | 108 | .flags = FORMAT_FLAGS_PACKED, |
114 | }, { | 109 | }, { |
115 | .name = "32 bpp RGB, le", | 110 | .name = "32 bpp RGB, le", |
116 | .fourcc = V4L2_PIX_FMT_BGR32, | 111 | .fourcc = V4L2_PIX_FMT_BGR32, |
117 | .depth = 32, | 112 | .depth = 32, |
118 | .flags = FORMAT_FLAGS_PACKED, | 113 | .flags = FORMAT_FLAGS_PACKED, |
119 | }, { | 114 | }, { |
120 | .name = "32 bpp RGB, be", | 115 | .name = "32 bpp RGB, be", |
121 | .fourcc = V4L2_PIX_FMT_RGB32, | 116 | .fourcc = V4L2_PIX_FMT_RGB32, |
122 | .depth = 32, | 117 | .depth = 32, |
123 | .flags = FORMAT_FLAGS_PACKED, | 118 | .flags = FORMAT_FLAGS_PACKED, |
124 | }, { | 119 | }, { |
125 | .name = "4:2:2, packed, YUYV", | 120 | .name = "4:2:2, packed, YUYV", |
126 | .fourcc = V4L2_PIX_FMT_YUYV, | 121 | .fourcc = V4L2_PIX_FMT_YUYV, |
127 | .depth = 16, | 122 | .depth = 16, |
128 | .flags = FORMAT_FLAGS_PACKED, | 123 | .flags = FORMAT_FLAGS_PACKED, |
129 | }, { | 124 | }, { |
130 | .name = "4:2:2, packed, UYVY", | 125 | .name = "4:2:2, packed, UYVY", |
131 | .fourcc = V4L2_PIX_FMT_UYVY, | 126 | .fourcc = V4L2_PIX_FMT_UYVY, |
132 | .depth = 16, | 127 | .depth = 16, |
133 | .flags = FORMAT_FLAGS_PACKED, | 128 | .flags = FORMAT_FLAGS_PACKED, |
134 | }, | 129 | }, |
135 | }; | 130 | }; |
136 | 131 | ||
137 | static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) | 132 | static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) |
138 | { | 133 | { |
139 | unsigned int i; | 134 | unsigned int i; |
140 | 135 | ||
141 | for (i = 0; i < ARRAY_SIZE(formats); i++) | 136 | for (i = 0; i < ARRAY_SIZE(formats); i++) |
142 | if (formats[i].fourcc == fourcc) | 137 | if (formats[i].fourcc == fourcc) |
143 | return formats+i; | 138 | return formats+i; |
144 | 139 | ||
145 | printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); | 140 | printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); |
146 | return NULL; | 141 | return NULL; |
147 | } | 142 | } |
148 | 143 | ||
149 | /* ------------------------------------------------------------------- */ | 144 | /* ------------------------------------------------------------------- */ |
150 | 145 | ||
151 | static const struct v4l2_queryctrl no_ctl = { | 146 | static const struct v4l2_queryctrl no_ctl = { |
152 | .name = "42", | 147 | .name = "42", |
153 | .flags = V4L2_CTRL_FLAG_DISABLED, | 148 | .flags = V4L2_CTRL_FLAG_DISABLED, |
154 | }; | 149 | }; |
155 | 150 | ||
156 | static struct cx23885_ctrl cx23885_ctls[] = { | 151 | static struct cx23885_ctrl cx23885_ctls[] = { |
157 | /* --- video --- */ | 152 | /* --- video --- */ |
158 | { | 153 | { |
159 | .v = { | 154 | .v = { |
160 | .id = V4L2_CID_BRIGHTNESS, | 155 | .id = V4L2_CID_BRIGHTNESS, |
161 | .name = "Brightness", | 156 | .name = "Brightness", |
162 | .minimum = 0x00, | 157 | .minimum = 0x00, |
163 | .maximum = 0xff, | 158 | .maximum = 0xff, |
164 | .step = 1, | 159 | .step = 1, |
165 | .default_value = 0x7f, | 160 | .default_value = 0x7f, |
166 | .type = V4L2_CTRL_TYPE_INTEGER, | 161 | .type = V4L2_CTRL_TYPE_INTEGER, |
167 | }, | 162 | }, |
168 | .off = 128, | 163 | .off = 128, |
169 | .reg = LUMA_CTRL, | 164 | .reg = LUMA_CTRL, |
170 | .mask = 0x00ff, | 165 | .mask = 0x00ff, |
171 | .shift = 0, | 166 | .shift = 0, |
172 | }, { | 167 | }, { |
173 | .v = { | 168 | .v = { |
174 | .id = V4L2_CID_CONTRAST, | 169 | .id = V4L2_CID_CONTRAST, |
175 | .name = "Contrast", | 170 | .name = "Contrast", |
176 | .minimum = 0, | 171 | .minimum = 0, |
177 | .maximum = 0xff, | 172 | .maximum = 0xff, |
178 | .step = 1, | 173 | .step = 1, |
179 | .default_value = 0x3f, | 174 | .default_value = 0x3f, |
180 | .type = V4L2_CTRL_TYPE_INTEGER, | 175 | .type = V4L2_CTRL_TYPE_INTEGER, |
181 | }, | 176 | }, |
182 | .off = 0, | 177 | .off = 0, |
183 | .reg = LUMA_CTRL, | 178 | .reg = LUMA_CTRL, |
184 | .mask = 0xff00, | 179 | .mask = 0xff00, |
185 | .shift = 8, | 180 | .shift = 8, |
186 | }, { | 181 | }, { |
187 | .v = { | 182 | .v = { |
188 | .id = V4L2_CID_HUE, | 183 | .id = V4L2_CID_HUE, |
189 | .name = "Hue", | 184 | .name = "Hue", |
190 | .minimum = 0, | 185 | .minimum = 0, |
191 | .maximum = 0xff, | 186 | .maximum = 0xff, |
192 | .step = 1, | 187 | .step = 1, |
193 | .default_value = 0x7f, | 188 | .default_value = 0x7f, |
194 | .type = V4L2_CTRL_TYPE_INTEGER, | 189 | .type = V4L2_CTRL_TYPE_INTEGER, |
195 | }, | 190 | }, |
196 | .off = 128, | 191 | .off = 128, |
197 | .reg = CHROMA_CTRL, | 192 | .reg = CHROMA_CTRL, |
198 | .mask = 0xff0000, | 193 | .mask = 0xff0000, |
199 | .shift = 16, | 194 | .shift = 16, |
200 | }, { | 195 | }, { |
201 | /* strictly, this only describes only U saturation. | 196 | /* strictly, this only describes only U saturation. |
202 | * V saturation is handled specially through code. | 197 | * V saturation is handled specially through code. |
203 | */ | 198 | */ |
204 | .v = { | 199 | .v = { |
205 | .id = V4L2_CID_SATURATION, | 200 | .id = V4L2_CID_SATURATION, |
206 | .name = "Saturation", | 201 | .name = "Saturation", |
207 | .minimum = 0, | 202 | .minimum = 0, |
208 | .maximum = 0xff, | 203 | .maximum = 0xff, |
209 | .step = 1, | 204 | .step = 1, |
210 | .default_value = 0x7f, | 205 | .default_value = 0x7f, |
211 | .type = V4L2_CTRL_TYPE_INTEGER, | 206 | .type = V4L2_CTRL_TYPE_INTEGER, |
212 | }, | 207 | }, |
213 | .off = 0, | 208 | .off = 0, |
214 | .reg = CHROMA_CTRL, | 209 | .reg = CHROMA_CTRL, |
215 | .mask = 0x00ff, | 210 | .mask = 0x00ff, |
216 | .shift = 0, | 211 | .shift = 0, |
217 | }, { | 212 | }, { |
218 | /* --- audio --- */ | 213 | /* --- audio --- */ |
219 | .v = { | 214 | .v = { |
220 | .id = V4L2_CID_AUDIO_MUTE, | 215 | .id = V4L2_CID_AUDIO_MUTE, |
221 | .name = "Mute", | 216 | .name = "Mute", |
222 | .minimum = 0, | 217 | .minimum = 0, |
223 | .maximum = 1, | 218 | .maximum = 1, |
224 | .default_value = 1, | 219 | .default_value = 1, |
225 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 220 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
226 | }, | 221 | }, |
227 | .reg = PATH1_CTL1, | 222 | .reg = PATH1_CTL1, |
228 | .mask = (0x1f << 24), | 223 | .mask = (0x1f << 24), |
229 | .shift = 24, | 224 | .shift = 24, |
230 | }, { | 225 | }, { |
231 | .v = { | 226 | .v = { |
232 | .id = V4L2_CID_AUDIO_VOLUME, | 227 | .id = V4L2_CID_AUDIO_VOLUME, |
233 | .name = "Volume", | 228 | .name = "Volume", |
234 | .minimum = 0, | 229 | .minimum = 0, |
235 | .maximum = 0x3f, | 230 | .maximum = 0x3f, |
236 | .step = 1, | 231 | .step = 1, |
237 | .default_value = 0x3f, | 232 | .default_value = 0x3f, |
238 | .type = V4L2_CTRL_TYPE_INTEGER, | 233 | .type = V4L2_CTRL_TYPE_INTEGER, |
239 | }, | 234 | }, |
240 | .reg = PATH1_VOL_CTL, | 235 | .reg = PATH1_VOL_CTL, |
241 | .mask = 0xff, | 236 | .mask = 0xff, |
242 | .shift = 0, | 237 | .shift = 0, |
243 | } | 238 | } |
244 | }; | 239 | }; |
245 | static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); | 240 | static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); |
246 | 241 | ||
247 | /* Must be sorted from low to high control ID! */ | 242 | /* Must be sorted from low to high control ID! */ |
248 | static const u32 cx23885_user_ctrls[] = { | 243 | static const u32 cx23885_user_ctrls[] = { |
249 | V4L2_CID_USER_CLASS, | 244 | V4L2_CID_USER_CLASS, |
250 | V4L2_CID_BRIGHTNESS, | 245 | V4L2_CID_BRIGHTNESS, |
251 | V4L2_CID_CONTRAST, | 246 | V4L2_CID_CONTRAST, |
252 | V4L2_CID_SATURATION, | 247 | V4L2_CID_SATURATION, |
253 | V4L2_CID_HUE, | 248 | V4L2_CID_HUE, |
254 | V4L2_CID_AUDIO_VOLUME, | 249 | V4L2_CID_AUDIO_VOLUME, |
255 | V4L2_CID_AUDIO_MUTE, | 250 | V4L2_CID_AUDIO_MUTE, |
256 | 0 | 251 | 0 |
257 | }; | 252 | }; |
258 | 253 | ||
259 | static const u32 *ctrl_classes[] = { | 254 | static const u32 *ctrl_classes[] = { |
260 | cx23885_user_ctrls, | 255 | cx23885_user_ctrls, |
261 | NULL | 256 | NULL |
262 | }; | 257 | }; |
263 | 258 | ||
264 | static void cx23885_video_wakeup(struct cx23885_dev *dev, | 259 | static void cx23885_video_wakeup(struct cx23885_dev *dev, |
265 | struct cx23885_dmaqueue *q, u32 count) | 260 | struct cx23885_dmaqueue *q, u32 count) |
266 | { | 261 | { |
267 | struct cx23885_buffer *buf; | 262 | struct cx23885_buffer *buf; |
268 | int bc; | 263 | int bc; |
269 | 264 | ||
270 | for (bc = 0;; bc++) { | 265 | for (bc = 0;; bc++) { |
271 | if (list_empty(&q->active)) | 266 | if (list_empty(&q->active)) |
272 | break; | 267 | break; |
273 | buf = list_entry(q->active.next, | 268 | buf = list_entry(q->active.next, |
274 | struct cx23885_buffer, vb.queue); | 269 | struct cx23885_buffer, vb.queue); |
275 | 270 | ||
276 | /* count comes from the hw and is is 16bit wide -- | 271 | /* count comes from the hw and is is 16bit wide -- |
277 | * this trick handles wrap-arounds correctly for | 272 | * this trick handles wrap-arounds correctly for |
278 | * up to 32767 buffers in flight... */ | 273 | * up to 32767 buffers in flight... */ |
279 | if ((s16) (count - buf->count) < 0) | 274 | if ((s16) (count - buf->count) < 0) |
280 | break; | 275 | break; |
281 | 276 | ||
282 | do_gettimeofday(&buf->vb.ts); | 277 | do_gettimeofday(&buf->vb.ts); |
283 | dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, | 278 | dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, |
284 | count, buf->count); | 279 | count, buf->count); |
285 | buf->vb.state = VIDEOBUF_DONE; | 280 | buf->vb.state = VIDEOBUF_DONE; |
286 | list_del(&buf->vb.queue); | 281 | list_del(&buf->vb.queue); |
287 | wake_up(&buf->vb.done); | 282 | wake_up(&buf->vb.done); |
288 | } | 283 | } |
289 | if (list_empty(&q->active)) | 284 | if (list_empty(&q->active)) |
290 | del_timer(&q->timeout); | 285 | del_timer(&q->timeout); |
291 | else | 286 | else |
292 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 287 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
293 | if (bc != 1) | 288 | if (bc != 1) |
294 | printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", | 289 | printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", |
295 | __func__, bc); | 290 | __func__, bc); |
296 | } | 291 | } |
297 | 292 | ||
298 | static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) | 293 | static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) |
299 | { | 294 | { |
300 | dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", | 295 | dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", |
301 | __func__, | 296 | __func__, |
302 | (unsigned int)norm, | 297 | (unsigned int)norm, |
303 | v4l2_norm_to_name(norm)); | 298 | v4l2_norm_to_name(norm)); |
304 | 299 | ||
305 | dev->tvnorm = norm; | 300 | dev->tvnorm = norm; |
306 | 301 | ||
307 | /* Tell the analog tuner/demods */ | 302 | /* Tell the analog tuner/demods */ |
308 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); | 303 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); |
309 | 304 | ||
310 | /* Tell the internal A/V decoder */ | 305 | /* Tell the internal A/V decoder */ |
311 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); | 306 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); |
312 | 307 | ||
313 | return 0; | 308 | return 0; |
314 | } | 309 | } |
315 | 310 | ||
316 | static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, | 311 | static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, |
317 | struct pci_dev *pci, | 312 | struct pci_dev *pci, |
318 | struct video_device *template, | 313 | struct video_device *template, |
319 | char *type) | 314 | char *type) |
320 | { | 315 | { |
321 | struct video_device *vfd; | 316 | struct video_device *vfd; |
322 | dprintk(1, "%s()\n", __func__); | 317 | dprintk(1, "%s()\n", __func__); |
323 | 318 | ||
324 | vfd = video_device_alloc(); | 319 | vfd = video_device_alloc(); |
325 | if (NULL == vfd) | 320 | if (NULL == vfd) |
326 | return NULL; | 321 | return NULL; |
327 | *vfd = *template; | 322 | *vfd = *template; |
328 | vfd->minor = -1; | 323 | vfd->minor = -1; |
329 | vfd->parent = &pci->dev; | 324 | vfd->parent = &pci->dev; |
330 | vfd->release = video_device_release; | 325 | vfd->release = video_device_release; |
331 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | 326 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", |
332 | dev->name, type, cx23885_boards[dev->board].name); | 327 | dev->name, type, cx23885_boards[dev->board].name); |
333 | return vfd; | 328 | return vfd; |
334 | } | 329 | } |
335 | 330 | ||
336 | static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) | 331 | static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) |
337 | { | 332 | { |
338 | int i; | 333 | int i; |
339 | 334 | ||
340 | if (qctrl->id < V4L2_CID_BASE || | 335 | if (qctrl->id < V4L2_CID_BASE || |
341 | qctrl->id >= V4L2_CID_LASTP1) | 336 | qctrl->id >= V4L2_CID_LASTP1) |
342 | return -EINVAL; | 337 | return -EINVAL; |
343 | for (i = 0; i < CX23885_CTLS; i++) | 338 | for (i = 0; i < CX23885_CTLS; i++) |
344 | if (cx23885_ctls[i].v.id == qctrl->id) | 339 | if (cx23885_ctls[i].v.id == qctrl->id) |
345 | break; | 340 | break; |
346 | if (i == CX23885_CTLS) { | 341 | if (i == CX23885_CTLS) { |
347 | *qctrl = no_ctl; | 342 | *qctrl = no_ctl; |
348 | return 0; | 343 | return 0; |
349 | } | 344 | } |
350 | *qctrl = cx23885_ctls[i].v; | 345 | *qctrl = cx23885_ctls[i].v; |
351 | return 0; | 346 | return 0; |
352 | } | 347 | } |
353 | 348 | ||
354 | /* ------------------------------------------------------------------- */ | 349 | /* ------------------------------------------------------------------- */ |
355 | /* resource management */ | 350 | /* resource management */ |
356 | 351 | ||
357 | static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, | 352 | static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, |
358 | unsigned int bit) | 353 | unsigned int bit) |
359 | { | 354 | { |
360 | dprintk(1, "%s()\n", __func__); | 355 | dprintk(1, "%s()\n", __func__); |
361 | if (fh->resources & bit) | 356 | if (fh->resources & bit) |
362 | /* have it already allocated */ | 357 | /* have it already allocated */ |
363 | return 1; | 358 | return 1; |
364 | 359 | ||
365 | /* is it free? */ | 360 | /* is it free? */ |
366 | mutex_lock(&dev->lock); | 361 | mutex_lock(&dev->lock); |
367 | if (dev->resources & bit) { | 362 | if (dev->resources & bit) { |
368 | /* no, someone else uses it */ | 363 | /* no, someone else uses it */ |
369 | mutex_unlock(&dev->lock); | 364 | mutex_unlock(&dev->lock); |
370 | return 0; | 365 | return 0; |
371 | } | 366 | } |
372 | /* it's free, grab it */ | 367 | /* it's free, grab it */ |
373 | fh->resources |= bit; | 368 | fh->resources |= bit; |
374 | dev->resources |= bit; | 369 | dev->resources |= bit; |
375 | dprintk(1, "res: get %d\n", bit); | 370 | dprintk(1, "res: get %d\n", bit); |
376 | mutex_unlock(&dev->lock); | 371 | mutex_unlock(&dev->lock); |
377 | return 1; | 372 | return 1; |
378 | } | 373 | } |
379 | 374 | ||
380 | static int res_check(struct cx23885_fh *fh, unsigned int bit) | 375 | static int res_check(struct cx23885_fh *fh, unsigned int bit) |
381 | { | 376 | { |
382 | return fh->resources & bit; | 377 | return fh->resources & bit; |
383 | } | 378 | } |
384 | 379 | ||
385 | static int res_locked(struct cx23885_dev *dev, unsigned int bit) | 380 | static int res_locked(struct cx23885_dev *dev, unsigned int bit) |
386 | { | 381 | { |
387 | return dev->resources & bit; | 382 | return dev->resources & bit; |
388 | } | 383 | } |
389 | 384 | ||
390 | static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, | 385 | static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, |
391 | unsigned int bits) | 386 | unsigned int bits) |
392 | { | 387 | { |
393 | BUG_ON((fh->resources & bits) != bits); | 388 | BUG_ON((fh->resources & bits) != bits); |
394 | dprintk(1, "%s()\n", __func__); | 389 | dprintk(1, "%s()\n", __func__); |
395 | 390 | ||
396 | mutex_lock(&dev->lock); | 391 | mutex_lock(&dev->lock); |
397 | fh->resources &= ~bits; | 392 | fh->resources &= ~bits; |
398 | dev->resources &= ~bits; | 393 | dev->resources &= ~bits; |
399 | dprintk(1, "res: put %d\n", bits); | 394 | dprintk(1, "res: put %d\n", bits); |
400 | mutex_unlock(&dev->lock); | 395 | mutex_unlock(&dev->lock); |
401 | } | 396 | } |
402 | 397 | ||
403 | static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) | 398 | static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) |
404 | { | 399 | { |
405 | struct v4l2_routing route; | 400 | struct v4l2_routing route; |
406 | memset(&route, 0, sizeof(route)); | 401 | memset(&route, 0, sizeof(route)); |
407 | 402 | ||
408 | dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", | 403 | dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", |
409 | __func__, | 404 | __func__, |
410 | input, INPUT(input)->vmux, | 405 | input, INPUT(input)->vmux, |
411 | INPUT(input)->gpio0, INPUT(input)->gpio1, | 406 | INPUT(input)->gpio0, INPUT(input)->gpio1, |
412 | INPUT(input)->gpio2, INPUT(input)->gpio3); | 407 | INPUT(input)->gpio2, INPUT(input)->gpio3); |
413 | dev->input = input; | 408 | dev->input = input; |
414 | 409 | ||
415 | route.input = INPUT(input)->vmux; | 410 | route.input = INPUT(input)->vmux; |
416 | 411 | ||
417 | /* Tell the internal A/V decoder */ | 412 | /* Tell the internal A/V decoder */ |
418 | cx23885_call_i2c_clients(&dev->i2c_bus[2], | 413 | cx23885_call_i2c_clients(&dev->i2c_bus[2], |
419 | VIDIOC_INT_S_VIDEO_ROUTING, &route); | 414 | VIDIOC_INT_S_VIDEO_ROUTING, &route); |
420 | 415 | ||
421 | return 0; | 416 | return 0; |
422 | } | 417 | } |
423 | 418 | ||
424 | /* ------------------------------------------------------------------ */ | 419 | /* ------------------------------------------------------------------ */ |
425 | static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, | 420 | static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, |
426 | unsigned int height, enum v4l2_field field) | 421 | unsigned int height, enum v4l2_field field) |
427 | { | 422 | { |
428 | dprintk(1, "%s()\n", __func__); | 423 | dprintk(1, "%s()\n", __func__); |
429 | return 0; | 424 | return 0; |
430 | } | 425 | } |
431 | 426 | ||
432 | static int cx23885_start_video_dma(struct cx23885_dev *dev, | 427 | static int cx23885_start_video_dma(struct cx23885_dev *dev, |
433 | struct cx23885_dmaqueue *q, | 428 | struct cx23885_dmaqueue *q, |
434 | struct cx23885_buffer *buf) | 429 | struct cx23885_buffer *buf) |
435 | { | 430 | { |
436 | dprintk(1, "%s()\n", __func__); | 431 | dprintk(1, "%s()\n", __func__); |
437 | 432 | ||
438 | /* setup fifo + format */ | 433 | /* setup fifo + format */ |
439 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], | 434 | cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], |
440 | buf->bpl, buf->risc.dma); | 435 | buf->bpl, buf->risc.dma); |
441 | cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); | 436 | cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); |
442 | 437 | ||
443 | /* reset counter */ | 438 | /* reset counter */ |
444 | cx_write(VID_A_GPCNT_CTL, 3); | 439 | cx_write(VID_A_GPCNT_CTL, 3); |
445 | q->count = 1; | 440 | q->count = 1; |
446 | 441 | ||
447 | /* enable irq */ | 442 | /* enable irq */ |
448 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); | 443 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); |
449 | cx_set(VID_A_INT_MSK, 0x000011); | 444 | cx_set(VID_A_INT_MSK, 0x000011); |
450 | 445 | ||
451 | /* start dma */ | 446 | /* start dma */ |
452 | cx_set(DEV_CNTRL2, (1<<5)); | 447 | cx_set(DEV_CNTRL2, (1<<5)); |
453 | cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ | 448 | cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ |
454 | 449 | ||
455 | return 0; | 450 | return 0; |
456 | } | 451 | } |
457 | 452 | ||
458 | 453 | ||
459 | static int cx23885_restart_video_queue(struct cx23885_dev *dev, | 454 | static int cx23885_restart_video_queue(struct cx23885_dev *dev, |
460 | struct cx23885_dmaqueue *q) | 455 | struct cx23885_dmaqueue *q) |
461 | { | 456 | { |
462 | struct cx23885_buffer *buf, *prev; | 457 | struct cx23885_buffer *buf, *prev; |
463 | struct list_head *item; | 458 | struct list_head *item; |
464 | dprintk(1, "%s()\n", __func__); | 459 | dprintk(1, "%s()\n", __func__); |
465 | 460 | ||
466 | if (!list_empty(&q->active)) { | 461 | if (!list_empty(&q->active)) { |
467 | buf = list_entry(q->active.next, struct cx23885_buffer, | 462 | buf = list_entry(q->active.next, struct cx23885_buffer, |
468 | vb.queue); | 463 | vb.queue); |
469 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | 464 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", |
470 | buf, buf->vb.i); | 465 | buf, buf->vb.i); |
471 | cx23885_start_video_dma(dev, q, buf); | 466 | cx23885_start_video_dma(dev, q, buf); |
472 | list_for_each(item, &q->active) { | 467 | list_for_each(item, &q->active) { |
473 | buf = list_entry(item, struct cx23885_buffer, | 468 | buf = list_entry(item, struct cx23885_buffer, |
474 | vb.queue); | 469 | vb.queue); |
475 | buf->count = q->count++; | 470 | buf->count = q->count++; |
476 | } | 471 | } |
477 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 472 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
478 | return 0; | 473 | return 0; |
479 | } | 474 | } |
480 | 475 | ||
481 | prev = NULL; | 476 | prev = NULL; |
482 | for (;;) { | 477 | for (;;) { |
483 | if (list_empty(&q->queued)) | 478 | if (list_empty(&q->queued)) |
484 | return 0; | 479 | return 0; |
485 | buf = list_entry(q->queued.next, struct cx23885_buffer, | 480 | buf = list_entry(q->queued.next, struct cx23885_buffer, |
486 | vb.queue); | 481 | vb.queue); |
487 | if (NULL == prev) { | 482 | if (NULL == prev) { |
488 | list_move_tail(&buf->vb.queue, &q->active); | 483 | list_move_tail(&buf->vb.queue, &q->active); |
489 | cx23885_start_video_dma(dev, q, buf); | 484 | cx23885_start_video_dma(dev, q, buf); |
490 | buf->vb.state = VIDEOBUF_ACTIVE; | 485 | buf->vb.state = VIDEOBUF_ACTIVE; |
491 | buf->count = q->count++; | 486 | buf->count = q->count++; |
492 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 487 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
493 | dprintk(2, "[%p/%d] restart_queue - first active\n", | 488 | dprintk(2, "[%p/%d] restart_queue - first active\n", |
494 | buf, buf->vb.i); | 489 | buf, buf->vb.i); |
495 | 490 | ||
496 | } else if (prev->vb.width == buf->vb.width && | 491 | } else if (prev->vb.width == buf->vb.width && |
497 | prev->vb.height == buf->vb.height && | 492 | prev->vb.height == buf->vb.height && |
498 | prev->fmt == buf->fmt) { | 493 | prev->fmt == buf->fmt) { |
499 | list_move_tail(&buf->vb.queue, &q->active); | 494 | list_move_tail(&buf->vb.queue, &q->active); |
500 | buf->vb.state = VIDEOBUF_ACTIVE; | 495 | buf->vb.state = VIDEOBUF_ACTIVE; |
501 | buf->count = q->count++; | 496 | buf->count = q->count++; |
502 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 497 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
503 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ | 498 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ |
504 | dprintk(2, "[%p/%d] restart_queue - move to active\n", | 499 | dprintk(2, "[%p/%d] restart_queue - move to active\n", |
505 | buf, buf->vb.i); | 500 | buf, buf->vb.i); |
506 | } else { | 501 | } else { |
507 | return 0; | 502 | return 0; |
508 | } | 503 | } |
509 | prev = buf; | 504 | prev = buf; |
510 | } | 505 | } |
511 | } | 506 | } |
512 | 507 | ||
513 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, | 508 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, |
514 | unsigned int *size) | 509 | unsigned int *size) |
515 | { | 510 | { |
516 | struct cx23885_fh *fh = q->priv_data; | 511 | struct cx23885_fh *fh = q->priv_data; |
517 | 512 | ||
518 | *size = fh->fmt->depth*fh->width*fh->height >> 3; | 513 | *size = fh->fmt->depth*fh->width*fh->height >> 3; |
519 | if (0 == *count) | 514 | if (0 == *count) |
520 | *count = 32; | 515 | *count = 32; |
521 | while (*size * *count > vid_limit * 1024 * 1024) | 516 | while (*size * *count > vid_limit * 1024 * 1024) |
522 | (*count)--; | 517 | (*count)--; |
523 | return 0; | 518 | return 0; |
524 | } | 519 | } |
525 | 520 | ||
526 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | 521 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, |
527 | enum v4l2_field field) | 522 | enum v4l2_field field) |
528 | { | 523 | { |
529 | struct cx23885_fh *fh = q->priv_data; | 524 | struct cx23885_fh *fh = q->priv_data; |
530 | struct cx23885_dev *dev = fh->dev; | 525 | struct cx23885_dev *dev = fh->dev; |
531 | struct cx23885_buffer *buf = | 526 | struct cx23885_buffer *buf = |
532 | container_of(vb, struct cx23885_buffer, vb); | 527 | container_of(vb, struct cx23885_buffer, vb); |
533 | int rc, init_buffer = 0; | 528 | int rc, init_buffer = 0; |
534 | u32 line0_offset, line1_offset; | 529 | u32 line0_offset, line1_offset; |
535 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | 530 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); |
536 | 531 | ||
537 | BUG_ON(NULL == fh->fmt); | 532 | BUG_ON(NULL == fh->fmt); |
538 | if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || | 533 | if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || |
539 | fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) | 534 | fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) |
540 | return -EINVAL; | 535 | return -EINVAL; |
541 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | 536 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; |
542 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | 537 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) |
543 | return -EINVAL; | 538 | return -EINVAL; |
544 | 539 | ||
545 | if (buf->fmt != fh->fmt || | 540 | if (buf->fmt != fh->fmt || |
546 | buf->vb.width != fh->width || | 541 | buf->vb.width != fh->width || |
547 | buf->vb.height != fh->height || | 542 | buf->vb.height != fh->height || |
548 | buf->vb.field != field) { | 543 | buf->vb.field != field) { |
549 | buf->fmt = fh->fmt; | 544 | buf->fmt = fh->fmt; |
550 | buf->vb.width = fh->width; | 545 | buf->vb.width = fh->width; |
551 | buf->vb.height = fh->height; | 546 | buf->vb.height = fh->height; |
552 | buf->vb.field = field; | 547 | buf->vb.field = field; |
553 | init_buffer = 1; | 548 | init_buffer = 1; |
554 | } | 549 | } |
555 | 550 | ||
556 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 551 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
557 | init_buffer = 1; | 552 | init_buffer = 1; |
558 | rc = videobuf_iolock(q, &buf->vb, NULL); | 553 | rc = videobuf_iolock(q, &buf->vb, NULL); |
559 | if (0 != rc) | 554 | if (0 != rc) |
560 | goto fail; | 555 | goto fail; |
561 | } | 556 | } |
562 | 557 | ||
563 | if (init_buffer) { | 558 | if (init_buffer) { |
564 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; | 559 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; |
565 | switch (buf->vb.field) { | 560 | switch (buf->vb.field) { |
566 | case V4L2_FIELD_TOP: | 561 | case V4L2_FIELD_TOP: |
567 | cx23885_risc_buffer(dev->pci, &buf->risc, | 562 | cx23885_risc_buffer(dev->pci, &buf->risc, |
568 | dma->sglist, 0, UNSET, | 563 | dma->sglist, 0, UNSET, |
569 | buf->bpl, 0, buf->vb.height); | 564 | buf->bpl, 0, buf->vb.height); |
570 | break; | 565 | break; |
571 | case V4L2_FIELD_BOTTOM: | 566 | case V4L2_FIELD_BOTTOM: |
572 | cx23885_risc_buffer(dev->pci, &buf->risc, | 567 | cx23885_risc_buffer(dev->pci, &buf->risc, |
573 | dma->sglist, UNSET, 0, | 568 | dma->sglist, UNSET, 0, |
574 | buf->bpl, 0, buf->vb.height); | 569 | buf->bpl, 0, buf->vb.height); |
575 | break; | 570 | break; |
576 | case V4L2_FIELD_INTERLACED: | 571 | case V4L2_FIELD_INTERLACED: |
577 | if (dev->tvnorm & V4L2_STD_NTSC) { | 572 | if (dev->tvnorm & V4L2_STD_NTSC) { |
578 | /* cx25840 transmits NTSC bottom field first */ | 573 | /* cx25840 transmits NTSC bottom field first */ |
579 | dprintk(1, "%s() Creating NTSC risc\n", | 574 | dprintk(1, "%s() Creating NTSC risc\n", |
580 | __func__); | 575 | __func__); |
581 | line0_offset = buf->bpl; | 576 | line0_offset = buf->bpl; |
582 | line1_offset = 0; | 577 | line1_offset = 0; |
583 | } else { | 578 | } else { |
584 | /* All other formats are top field first */ | 579 | /* All other formats are top field first */ |
585 | dprintk(1, "%s() Creating PAL/SECAM risc\n", | 580 | dprintk(1, "%s() Creating PAL/SECAM risc\n", |
586 | __func__); | 581 | __func__); |
587 | line0_offset = 0; | 582 | line0_offset = 0; |
588 | line1_offset = buf->bpl; | 583 | line1_offset = buf->bpl; |
589 | } | 584 | } |
590 | cx23885_risc_buffer(dev->pci, &buf->risc, | 585 | cx23885_risc_buffer(dev->pci, &buf->risc, |
591 | dma->sglist, line0_offset, | 586 | dma->sglist, line0_offset, |
592 | line1_offset, | 587 | line1_offset, |
593 | buf->bpl, buf->bpl, | 588 | buf->bpl, buf->bpl, |
594 | buf->vb.height >> 1); | 589 | buf->vb.height >> 1); |
595 | break; | 590 | break; |
596 | case V4L2_FIELD_SEQ_TB: | 591 | case V4L2_FIELD_SEQ_TB: |
597 | cx23885_risc_buffer(dev->pci, &buf->risc, | 592 | cx23885_risc_buffer(dev->pci, &buf->risc, |
598 | dma->sglist, | 593 | dma->sglist, |
599 | 0, buf->bpl * (buf->vb.height >> 1), | 594 | 0, buf->bpl * (buf->vb.height >> 1), |
600 | buf->bpl, 0, | 595 | buf->bpl, 0, |
601 | buf->vb.height >> 1); | 596 | buf->vb.height >> 1); |
602 | break; | 597 | break; |
603 | case V4L2_FIELD_SEQ_BT: | 598 | case V4L2_FIELD_SEQ_BT: |
604 | cx23885_risc_buffer(dev->pci, &buf->risc, | 599 | cx23885_risc_buffer(dev->pci, &buf->risc, |
605 | dma->sglist, | 600 | dma->sglist, |
606 | buf->bpl * (buf->vb.height >> 1), 0, | 601 | buf->bpl * (buf->vb.height >> 1), 0, |
607 | buf->bpl, 0, | 602 | buf->bpl, 0, |
608 | buf->vb.height >> 1); | 603 | buf->vb.height >> 1); |
609 | break; | 604 | break; |
610 | default: | 605 | default: |
611 | BUG(); | 606 | BUG(); |
612 | } | 607 | } |
613 | } | 608 | } |
614 | dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | 609 | dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", |
615 | buf, buf->vb.i, | 610 | buf, buf->vb.i, |
616 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, | 611 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, |
617 | (unsigned long)buf->risc.dma); | 612 | (unsigned long)buf->risc.dma); |
618 | 613 | ||
619 | buf->vb.state = VIDEOBUF_PREPARED; | 614 | buf->vb.state = VIDEOBUF_PREPARED; |
620 | return 0; | 615 | return 0; |
621 | 616 | ||
622 | fail: | 617 | fail: |
623 | cx23885_free_buffer(q, buf); | 618 | cx23885_free_buffer(q, buf); |
624 | return rc; | 619 | return rc; |
625 | } | 620 | } |
626 | 621 | ||
627 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | 622 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) |
628 | { | 623 | { |
629 | struct cx23885_buffer *buf = container_of(vb, | 624 | struct cx23885_buffer *buf = container_of(vb, |
630 | struct cx23885_buffer, vb); | 625 | struct cx23885_buffer, vb); |
631 | struct cx23885_buffer *prev; | 626 | struct cx23885_buffer *prev; |
632 | struct cx23885_fh *fh = vq->priv_data; | 627 | struct cx23885_fh *fh = vq->priv_data; |
633 | struct cx23885_dev *dev = fh->dev; | 628 | struct cx23885_dev *dev = fh->dev; |
634 | struct cx23885_dmaqueue *q = &dev->vidq; | 629 | struct cx23885_dmaqueue *q = &dev->vidq; |
635 | 630 | ||
636 | /* add jump to stopper */ | 631 | /* add jump to stopper */ |
637 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | 632 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); |
638 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | 633 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); |
639 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | 634 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ |
640 | 635 | ||
641 | if (!list_empty(&q->queued)) { | 636 | if (!list_empty(&q->queued)) { |
642 | list_add_tail(&buf->vb.queue, &q->queued); | 637 | list_add_tail(&buf->vb.queue, &q->queued); |
643 | buf->vb.state = VIDEOBUF_QUEUED; | 638 | buf->vb.state = VIDEOBUF_QUEUED; |
644 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", | 639 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", |
645 | buf, buf->vb.i); | 640 | buf, buf->vb.i); |
646 | 641 | ||
647 | } else if (list_empty(&q->active)) { | 642 | } else if (list_empty(&q->active)) { |
648 | list_add_tail(&buf->vb.queue, &q->active); | 643 | list_add_tail(&buf->vb.queue, &q->active); |
649 | cx23885_start_video_dma(dev, q, buf); | 644 | cx23885_start_video_dma(dev, q, buf); |
650 | buf->vb.state = VIDEOBUF_ACTIVE; | 645 | buf->vb.state = VIDEOBUF_ACTIVE; |
651 | buf->count = q->count++; | 646 | buf->count = q->count++; |
652 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 647 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
653 | dprintk(2, "[%p/%d] buffer_queue - first active\n", | 648 | dprintk(2, "[%p/%d] buffer_queue - first active\n", |
654 | buf, buf->vb.i); | 649 | buf, buf->vb.i); |
655 | 650 | ||
656 | } else { | 651 | } else { |
657 | prev = list_entry(q->active.prev, struct cx23885_buffer, | 652 | prev = list_entry(q->active.prev, struct cx23885_buffer, |
658 | vb.queue); | 653 | vb.queue); |
659 | if (prev->vb.width == buf->vb.width && | 654 | if (prev->vb.width == buf->vb.width && |
660 | prev->vb.height == buf->vb.height && | 655 | prev->vb.height == buf->vb.height && |
661 | prev->fmt == buf->fmt) { | 656 | prev->fmt == buf->fmt) { |
662 | list_add_tail(&buf->vb.queue, &q->active); | 657 | list_add_tail(&buf->vb.queue, &q->active); |
663 | buf->vb.state = VIDEOBUF_ACTIVE; | 658 | buf->vb.state = VIDEOBUF_ACTIVE; |
664 | buf->count = q->count++; | 659 | buf->count = q->count++; |
665 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 660 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
666 | /* 64 bit bits 63-32 */ | 661 | /* 64 bit bits 63-32 */ |
667 | prev->risc.jmp[2] = cpu_to_le32(0); | 662 | prev->risc.jmp[2] = cpu_to_le32(0); |
668 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | 663 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", |
669 | buf, buf->vb.i); | 664 | buf, buf->vb.i); |
670 | 665 | ||
671 | } else { | 666 | } else { |
672 | list_add_tail(&buf->vb.queue, &q->queued); | 667 | list_add_tail(&buf->vb.queue, &q->queued); |
673 | buf->vb.state = VIDEOBUF_QUEUED; | 668 | buf->vb.state = VIDEOBUF_QUEUED; |
674 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", | 669 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", |
675 | buf, buf->vb.i); | 670 | buf, buf->vb.i); |
676 | } | 671 | } |
677 | } | 672 | } |
678 | } | 673 | } |
679 | 674 | ||
680 | static void buffer_release(struct videobuf_queue *q, | 675 | static void buffer_release(struct videobuf_queue *q, |
681 | struct videobuf_buffer *vb) | 676 | struct videobuf_buffer *vb) |
682 | { | 677 | { |
683 | struct cx23885_buffer *buf = container_of(vb, | 678 | struct cx23885_buffer *buf = container_of(vb, |
684 | struct cx23885_buffer, vb); | 679 | struct cx23885_buffer, vb); |
685 | 680 | ||
686 | cx23885_free_buffer(q, buf); | 681 | cx23885_free_buffer(q, buf); |
687 | } | 682 | } |
688 | 683 | ||
689 | static struct videobuf_queue_ops cx23885_video_qops = { | 684 | static struct videobuf_queue_ops cx23885_video_qops = { |
690 | .buf_setup = buffer_setup, | 685 | .buf_setup = buffer_setup, |
691 | .buf_prepare = buffer_prepare, | 686 | .buf_prepare = buffer_prepare, |
692 | .buf_queue = buffer_queue, | 687 | .buf_queue = buffer_queue, |
693 | .buf_release = buffer_release, | 688 | .buf_release = buffer_release, |
694 | }; | 689 | }; |
695 | 690 | ||
696 | static struct videobuf_queue *get_queue(struct cx23885_fh *fh) | 691 | static struct videobuf_queue *get_queue(struct cx23885_fh *fh) |
697 | { | 692 | { |
698 | switch (fh->type) { | 693 | switch (fh->type) { |
699 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 694 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
700 | return &fh->vidq; | 695 | return &fh->vidq; |
701 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 696 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
702 | return &fh->vbiq; | 697 | return &fh->vbiq; |
703 | default: | 698 | default: |
704 | BUG(); | 699 | BUG(); |
705 | return NULL; | 700 | return NULL; |
706 | } | 701 | } |
707 | } | 702 | } |
708 | 703 | ||
709 | static int get_resource(struct cx23885_fh *fh) | 704 | static int get_resource(struct cx23885_fh *fh) |
710 | { | 705 | { |
711 | switch (fh->type) { | 706 | switch (fh->type) { |
712 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 707 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
713 | return RESOURCE_VIDEO; | 708 | return RESOURCE_VIDEO; |
714 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 709 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
715 | return RESOURCE_VBI; | 710 | return RESOURCE_VBI; |
716 | default: | 711 | default: |
717 | BUG(); | 712 | BUG(); |
718 | return 0; | 713 | return 0; |
719 | } | 714 | } |
720 | } | 715 | } |
721 | 716 | ||
722 | static int video_open(struct file *file) | 717 | static int video_open(struct file *file) |
723 | { | 718 | { |
724 | int minor = video_devdata(file)->minor; | 719 | int minor = video_devdata(file)->minor; |
725 | struct cx23885_dev *h, *dev = NULL; | 720 | struct cx23885_dev *h, *dev = NULL; |
726 | struct cx23885_fh *fh; | 721 | struct cx23885_fh *fh; |
727 | struct list_head *list; | 722 | struct list_head *list; |
728 | enum v4l2_buf_type type = 0; | 723 | enum v4l2_buf_type type = 0; |
729 | int radio = 0; | 724 | int radio = 0; |
730 | 725 | ||
731 | lock_kernel(); | 726 | lock_kernel(); |
732 | list_for_each(list, &cx23885_devlist) { | 727 | list_for_each(list, &cx23885_devlist) { |
733 | h = list_entry(list, struct cx23885_dev, devlist); | 728 | h = list_entry(list, struct cx23885_dev, devlist); |
734 | if (h->video_dev && | 729 | if (h->video_dev && |
735 | h->video_dev->minor == minor) { | 730 | h->video_dev->minor == minor) { |
736 | dev = h; | 731 | dev = h; |
737 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 732 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
738 | } | 733 | } |
739 | if (h->vbi_dev && | 734 | if (h->vbi_dev && |
740 | h->vbi_dev->minor == minor) { | 735 | h->vbi_dev->minor == minor) { |
741 | dev = h; | 736 | dev = h; |
742 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 737 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
743 | } | 738 | } |
744 | if (h->radio_dev && | 739 | if (h->radio_dev && |
745 | h->radio_dev->minor == minor) { | 740 | h->radio_dev->minor == minor) { |
746 | radio = 1; | 741 | radio = 1; |
747 | dev = h; | 742 | dev = h; |
748 | } | 743 | } |
749 | } | 744 | } |
750 | if (NULL == dev) { | 745 | if (NULL == dev) { |
751 | unlock_kernel(); | 746 | unlock_kernel(); |
752 | return -ENODEV; | 747 | return -ENODEV; |
753 | } | 748 | } |
754 | 749 | ||
755 | dprintk(1, "open minor=%d radio=%d type=%s\n", | 750 | dprintk(1, "open minor=%d radio=%d type=%s\n", |
756 | minor, radio, v4l2_type_names[type]); | 751 | minor, radio, v4l2_type_names[type]); |
757 | 752 | ||
758 | /* allocate + initialize per filehandle data */ | 753 | /* allocate + initialize per filehandle data */ |
759 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 754 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
760 | if (NULL == fh) { | 755 | if (NULL == fh) { |
761 | unlock_kernel(); | 756 | unlock_kernel(); |
762 | return -ENOMEM; | 757 | return -ENOMEM; |
763 | } | 758 | } |
764 | file->private_data = fh; | 759 | file->private_data = fh; |
765 | fh->dev = dev; | 760 | fh->dev = dev; |
766 | fh->radio = radio; | 761 | fh->radio = radio; |
767 | fh->type = type; | 762 | fh->type = type; |
768 | fh->width = 320; | 763 | fh->width = 320; |
769 | fh->height = 240; | 764 | fh->height = 240; |
770 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | 765 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
771 | 766 | ||
772 | videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, | 767 | videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, |
773 | &dev->pci->dev, &dev->slock, | 768 | &dev->pci->dev, &dev->slock, |
774 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 769 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
775 | V4L2_FIELD_INTERLACED, | 770 | V4L2_FIELD_INTERLACED, |
776 | sizeof(struct cx23885_buffer), | 771 | sizeof(struct cx23885_buffer), |
777 | fh); | 772 | fh); |
778 | 773 | ||
779 | dprintk(1, "post videobuf_queue_init()\n"); | 774 | dprintk(1, "post videobuf_queue_init()\n"); |
780 | 775 | ||
781 | unlock_kernel(); | 776 | unlock_kernel(); |
782 | 777 | ||
783 | return 0; | 778 | return 0; |
784 | } | 779 | } |
785 | 780 | ||
786 | static ssize_t video_read(struct file *file, char __user *data, | 781 | static ssize_t video_read(struct file *file, char __user *data, |
787 | size_t count, loff_t *ppos) | 782 | size_t count, loff_t *ppos) |
788 | { | 783 | { |
789 | struct cx23885_fh *fh = file->private_data; | 784 | struct cx23885_fh *fh = file->private_data; |
790 | 785 | ||
791 | switch (fh->type) { | 786 | switch (fh->type) { |
792 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 787 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
793 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | 788 | if (res_locked(fh->dev, RESOURCE_VIDEO)) |
794 | return -EBUSY; | 789 | return -EBUSY; |
795 | return videobuf_read_one(&fh->vidq, data, count, ppos, | 790 | return videobuf_read_one(&fh->vidq, data, count, ppos, |
796 | file->f_flags & O_NONBLOCK); | 791 | file->f_flags & O_NONBLOCK); |
797 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 792 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
798 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | 793 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) |
799 | return -EBUSY; | 794 | return -EBUSY; |
800 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, | 795 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, |
801 | file->f_flags & O_NONBLOCK); | 796 | file->f_flags & O_NONBLOCK); |
802 | default: | 797 | default: |
803 | BUG(); | 798 | BUG(); |
804 | return 0; | 799 | return 0; |
805 | } | 800 | } |
806 | } | 801 | } |
807 | 802 | ||
808 | static unsigned int video_poll(struct file *file, | 803 | static unsigned int video_poll(struct file *file, |
809 | struct poll_table_struct *wait) | 804 | struct poll_table_struct *wait) |
810 | { | 805 | { |
811 | struct cx23885_fh *fh = file->private_data; | 806 | struct cx23885_fh *fh = file->private_data; |
812 | struct cx23885_buffer *buf; | 807 | struct cx23885_buffer *buf; |
813 | 808 | ||
814 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | 809 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { |
815 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) | 810 | if (!res_get(fh->dev, fh, RESOURCE_VBI)) |
816 | return POLLERR; | 811 | return POLLERR; |
817 | return videobuf_poll_stream(file, &fh->vbiq, wait); | 812 | return videobuf_poll_stream(file, &fh->vbiq, wait); |
818 | } | 813 | } |
819 | 814 | ||
820 | if (res_check(fh, RESOURCE_VIDEO)) { | 815 | if (res_check(fh, RESOURCE_VIDEO)) { |
821 | /* streaming capture */ | 816 | /* streaming capture */ |
822 | if (list_empty(&fh->vidq.stream)) | 817 | if (list_empty(&fh->vidq.stream)) |
823 | return POLLERR; | 818 | return POLLERR; |
824 | buf = list_entry(fh->vidq.stream.next, | 819 | buf = list_entry(fh->vidq.stream.next, |
825 | struct cx23885_buffer, vb.stream); | 820 | struct cx23885_buffer, vb.stream); |
826 | } else { | 821 | } else { |
827 | /* read() capture */ | 822 | /* read() capture */ |
828 | buf = (struct cx23885_buffer *)fh->vidq.read_buf; | 823 | buf = (struct cx23885_buffer *)fh->vidq.read_buf; |
829 | if (NULL == buf) | 824 | if (NULL == buf) |
830 | return POLLERR; | 825 | return POLLERR; |
831 | } | 826 | } |
832 | poll_wait(file, &buf->vb.done, wait); | 827 | poll_wait(file, &buf->vb.done, wait); |
833 | if (buf->vb.state == VIDEOBUF_DONE || | 828 | if (buf->vb.state == VIDEOBUF_DONE || |
834 | buf->vb.state == VIDEOBUF_ERROR) | 829 | buf->vb.state == VIDEOBUF_ERROR) |
835 | return POLLIN|POLLRDNORM; | 830 | return POLLIN|POLLRDNORM; |
836 | return 0; | 831 | return 0; |
837 | } | 832 | } |
838 | 833 | ||
839 | static int video_release(struct file *file) | 834 | static int video_release(struct file *file) |
840 | { | 835 | { |
841 | struct cx23885_fh *fh = file->private_data; | 836 | struct cx23885_fh *fh = file->private_data; |
842 | struct cx23885_dev *dev = fh->dev; | 837 | struct cx23885_dev *dev = fh->dev; |
843 | 838 | ||
844 | /* turn off overlay */ | 839 | /* turn off overlay */ |
845 | if (res_check(fh, RESOURCE_OVERLAY)) { | 840 | if (res_check(fh, RESOURCE_OVERLAY)) { |
846 | /* FIXME */ | 841 | /* FIXME */ |
847 | res_free(dev, fh, RESOURCE_OVERLAY); | 842 | res_free(dev, fh, RESOURCE_OVERLAY); |
848 | } | 843 | } |
849 | 844 | ||
850 | /* stop video capture */ | 845 | /* stop video capture */ |
851 | if (res_check(fh, RESOURCE_VIDEO)) { | 846 | if (res_check(fh, RESOURCE_VIDEO)) { |
852 | videobuf_queue_cancel(&fh->vidq); | 847 | videobuf_queue_cancel(&fh->vidq); |
853 | res_free(dev, fh, RESOURCE_VIDEO); | 848 | res_free(dev, fh, RESOURCE_VIDEO); |
854 | } | 849 | } |
855 | if (fh->vidq.read_buf) { | 850 | if (fh->vidq.read_buf) { |
856 | buffer_release(&fh->vidq, fh->vidq.read_buf); | 851 | buffer_release(&fh->vidq, fh->vidq.read_buf); |
857 | kfree(fh->vidq.read_buf); | 852 | kfree(fh->vidq.read_buf); |
858 | } | 853 | } |
859 | 854 | ||
860 | /* stop vbi capture */ | 855 | /* stop vbi capture */ |
861 | if (res_check(fh, RESOURCE_VBI)) { | 856 | if (res_check(fh, RESOURCE_VBI)) { |
862 | if (fh->vbiq.streaming) | 857 | if (fh->vbiq.streaming) |
863 | videobuf_streamoff(&fh->vbiq); | 858 | videobuf_streamoff(&fh->vbiq); |
864 | if (fh->vbiq.reading) | 859 | if (fh->vbiq.reading) |
865 | videobuf_read_stop(&fh->vbiq); | 860 | videobuf_read_stop(&fh->vbiq); |
866 | res_free(dev, fh, RESOURCE_VBI); | 861 | res_free(dev, fh, RESOURCE_VBI); |
867 | } | 862 | } |
868 | 863 | ||
869 | videobuf_mmap_free(&fh->vidq); | 864 | videobuf_mmap_free(&fh->vidq); |
870 | file->private_data = NULL; | 865 | file->private_data = NULL; |
871 | kfree(fh); | 866 | kfree(fh); |
872 | 867 | ||
873 | /* We are not putting the tuner to sleep here on exit, because | 868 | /* We are not putting the tuner to sleep here on exit, because |
874 | * we want to use the mpeg encoder in another session to capture | 869 | * we want to use the mpeg encoder in another session to capture |
875 | * tuner video. Closing this will result in no video to the encoder. | 870 | * tuner video. Closing this will result in no video to the encoder. |
876 | */ | 871 | */ |
877 | 872 | ||
878 | return 0; | 873 | return 0; |
879 | } | 874 | } |
880 | 875 | ||
881 | static int video_mmap(struct file *file, struct vm_area_struct *vma) | 876 | static int video_mmap(struct file *file, struct vm_area_struct *vma) |
882 | { | 877 | { |
883 | struct cx23885_fh *fh = file->private_data; | 878 | struct cx23885_fh *fh = file->private_data; |
884 | 879 | ||
885 | return videobuf_mmap_mapper(get_queue(fh), vma); | 880 | return videobuf_mmap_mapper(get_queue(fh), vma); |
886 | } | 881 | } |
887 | 882 | ||
888 | /* ------------------------------------------------------------------ */ | 883 | /* ------------------------------------------------------------------ */ |
889 | /* VIDEO CTRL IOCTLS */ | 884 | /* VIDEO CTRL IOCTLS */ |
890 | 885 | ||
891 | static int cx23885_get_control(struct cx23885_dev *dev, | 886 | static int cx23885_get_control(struct cx23885_dev *dev, |
892 | struct v4l2_control *ctl) | 887 | struct v4l2_control *ctl) |
893 | { | 888 | { |
894 | dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); | 889 | dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); |
895 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); | 890 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); |
896 | return 0; | 891 | return 0; |
897 | } | 892 | } |
898 | 893 | ||
899 | static int cx23885_set_control(struct cx23885_dev *dev, | 894 | static int cx23885_set_control(struct cx23885_dev *dev, |
900 | struct v4l2_control *ctl) | 895 | struct v4l2_control *ctl) |
901 | { | 896 | { |
902 | dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" | 897 | dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" |
903 | " (disabled - no action)\n", __func__); | 898 | " (disabled - no action)\n", __func__); |
904 | return 0; | 899 | return 0; |
905 | } | 900 | } |
906 | 901 | ||
907 | static void init_controls(struct cx23885_dev *dev) | 902 | static void init_controls(struct cx23885_dev *dev) |
908 | { | 903 | { |
909 | struct v4l2_control ctrl; | 904 | struct v4l2_control ctrl; |
910 | int i; | 905 | int i; |
911 | 906 | ||
912 | for (i = 0; i < CX23885_CTLS; i++) { | 907 | for (i = 0; i < CX23885_CTLS; i++) { |
913 | ctrl.id = cx23885_ctls[i].v.id; | 908 | ctrl.id = cx23885_ctls[i].v.id; |
914 | ctrl.value = cx23885_ctls[i].v.default_value; | 909 | ctrl.value = cx23885_ctls[i].v.default_value; |
915 | 910 | ||
916 | cx23885_set_control(dev, &ctrl); | 911 | cx23885_set_control(dev, &ctrl); |
917 | } | 912 | } |
918 | } | 913 | } |
919 | 914 | ||
920 | /* ------------------------------------------------------------------ */ | 915 | /* ------------------------------------------------------------------ */ |
921 | /* VIDEO IOCTLS */ | 916 | /* VIDEO IOCTLS */ |
922 | 917 | ||
923 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | 918 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
924 | struct v4l2_format *f) | 919 | struct v4l2_format *f) |
925 | { | 920 | { |
926 | struct cx23885_fh *fh = priv; | 921 | struct cx23885_fh *fh = priv; |
927 | 922 | ||
928 | f->fmt.pix.width = fh->width; | 923 | f->fmt.pix.width = fh->width; |
929 | f->fmt.pix.height = fh->height; | 924 | f->fmt.pix.height = fh->height; |
930 | f->fmt.pix.field = fh->vidq.field; | 925 | f->fmt.pix.field = fh->vidq.field; |
931 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | 926 | f->fmt.pix.pixelformat = fh->fmt->fourcc; |
932 | f->fmt.pix.bytesperline = | 927 | f->fmt.pix.bytesperline = |
933 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | 928 | (f->fmt.pix.width * fh->fmt->depth) >> 3; |
934 | f->fmt.pix.sizeimage = | 929 | f->fmt.pix.sizeimage = |
935 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 930 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
936 | 931 | ||
937 | return 0; | 932 | return 0; |
938 | } | 933 | } |
939 | 934 | ||
940 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | 935 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
941 | struct v4l2_format *f) | 936 | struct v4l2_format *f) |
942 | { | 937 | { |
943 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 938 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
944 | struct cx23885_fmt *fmt; | 939 | struct cx23885_fmt *fmt; |
945 | enum v4l2_field field; | 940 | enum v4l2_field field; |
946 | unsigned int maxw, maxh; | 941 | unsigned int maxw, maxh; |
947 | 942 | ||
948 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 943 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
949 | if (NULL == fmt) | 944 | if (NULL == fmt) |
950 | return -EINVAL; | 945 | return -EINVAL; |
951 | 946 | ||
952 | field = f->fmt.pix.field; | 947 | field = f->fmt.pix.field; |
953 | maxw = norm_maxw(dev->tvnorm); | 948 | maxw = norm_maxw(dev->tvnorm); |
954 | maxh = norm_maxh(dev->tvnorm); | 949 | maxh = norm_maxh(dev->tvnorm); |
955 | 950 | ||
956 | if (V4L2_FIELD_ANY == field) { | 951 | if (V4L2_FIELD_ANY == field) { |
957 | field = (f->fmt.pix.height > maxh/2) | 952 | field = (f->fmt.pix.height > maxh/2) |
958 | ? V4L2_FIELD_INTERLACED | 953 | ? V4L2_FIELD_INTERLACED |
959 | : V4L2_FIELD_BOTTOM; | 954 | : V4L2_FIELD_BOTTOM; |
960 | } | 955 | } |
961 | 956 | ||
962 | switch (field) { | 957 | switch (field) { |
963 | case V4L2_FIELD_TOP: | 958 | case V4L2_FIELD_TOP: |
964 | case V4L2_FIELD_BOTTOM: | 959 | case V4L2_FIELD_BOTTOM: |
965 | maxh = maxh / 2; | 960 | maxh = maxh / 2; |
966 | break; | 961 | break; |
967 | case V4L2_FIELD_INTERLACED: | 962 | case V4L2_FIELD_INTERLACED: |
968 | break; | 963 | break; |
969 | default: | 964 | default: |
970 | return -EINVAL; | 965 | return -EINVAL; |
971 | } | 966 | } |
972 | 967 | ||
973 | f->fmt.pix.field = field; | 968 | f->fmt.pix.field = field; |
974 | if (f->fmt.pix.height < 32) | 969 | if (f->fmt.pix.height < 32) |
975 | f->fmt.pix.height = 32; | 970 | f->fmt.pix.height = 32; |
976 | if (f->fmt.pix.height > maxh) | 971 | if (f->fmt.pix.height > maxh) |
977 | f->fmt.pix.height = maxh; | 972 | f->fmt.pix.height = maxh; |
978 | if (f->fmt.pix.width < 48) | 973 | if (f->fmt.pix.width < 48) |
979 | f->fmt.pix.width = 48; | 974 | f->fmt.pix.width = 48; |
980 | if (f->fmt.pix.width > maxw) | 975 | if (f->fmt.pix.width > maxw) |
981 | f->fmt.pix.width = maxw; | 976 | f->fmt.pix.width = maxw; |
982 | f->fmt.pix.width &= ~0x03; | 977 | f->fmt.pix.width &= ~0x03; |
983 | f->fmt.pix.bytesperline = | 978 | f->fmt.pix.bytesperline = |
984 | (f->fmt.pix.width * fmt->depth) >> 3; | 979 | (f->fmt.pix.width * fmt->depth) >> 3; |
985 | f->fmt.pix.sizeimage = | 980 | f->fmt.pix.sizeimage = |
986 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 981 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
987 | 982 | ||
988 | return 0; | 983 | return 0; |
989 | } | 984 | } |
990 | 985 | ||
991 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 986 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
992 | struct v4l2_format *f) | 987 | struct v4l2_format *f) |
993 | { | 988 | { |
994 | struct cx23885_fh *fh = priv; | 989 | struct cx23885_fh *fh = priv; |
995 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 990 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
996 | int err; | 991 | int err; |
997 | 992 | ||
998 | dprintk(2, "%s()\n", __func__); | 993 | dprintk(2, "%s()\n", __func__); |
999 | err = vidioc_try_fmt_vid_cap(file, priv, f); | 994 | err = vidioc_try_fmt_vid_cap(file, priv, f); |
1000 | 995 | ||
1001 | if (0 != err) | 996 | if (0 != err) |
1002 | return err; | 997 | return err; |
1003 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 998 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1004 | fh->width = f->fmt.pix.width; | 999 | fh->width = f->fmt.pix.width; |
1005 | fh->height = f->fmt.pix.height; | 1000 | fh->height = f->fmt.pix.height; |
1006 | fh->vidq.field = f->fmt.pix.field; | 1001 | fh->vidq.field = f->fmt.pix.field; |
1007 | dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, | 1002 | dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, |
1008 | fh->width, fh->height, fh->vidq.field); | 1003 | fh->width, fh->height, fh->vidq.field); |
1009 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f); | 1004 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f); |
1010 | return 0; | 1005 | return 0; |
1011 | } | 1006 | } |
1012 | 1007 | ||
1013 | static int vidioc_querycap(struct file *file, void *priv, | 1008 | static int vidioc_querycap(struct file *file, void *priv, |
1014 | struct v4l2_capability *cap) | 1009 | struct v4l2_capability *cap) |
1015 | { | 1010 | { |
1016 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1011 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1017 | 1012 | ||
1018 | strcpy(cap->driver, "cx23885"); | 1013 | strcpy(cap->driver, "cx23885"); |
1019 | strlcpy(cap->card, cx23885_boards[dev->board].name, | 1014 | strlcpy(cap->card, cx23885_boards[dev->board].name, |
1020 | sizeof(cap->card)); | 1015 | sizeof(cap->card)); |
1021 | sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); | 1016 | sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); |
1022 | cap->version = CX23885_VERSION_CODE; | 1017 | cap->version = CX23885_VERSION_CODE; |
1023 | cap->capabilities = | 1018 | cap->capabilities = |
1024 | V4L2_CAP_VIDEO_CAPTURE | | 1019 | V4L2_CAP_VIDEO_CAPTURE | |
1025 | V4L2_CAP_READWRITE | | 1020 | V4L2_CAP_READWRITE | |
1026 | V4L2_CAP_STREAMING | | 1021 | V4L2_CAP_STREAMING | |
1027 | V4L2_CAP_VBI_CAPTURE; | 1022 | V4L2_CAP_VBI_CAPTURE; |
1028 | if (UNSET != dev->tuner_type) | 1023 | if (UNSET != dev->tuner_type) |
1029 | cap->capabilities |= V4L2_CAP_TUNER; | 1024 | cap->capabilities |= V4L2_CAP_TUNER; |
1030 | return 0; | 1025 | return 0; |
1031 | } | 1026 | } |
1032 | 1027 | ||
1033 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | 1028 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
1034 | struct v4l2_fmtdesc *f) | 1029 | struct v4l2_fmtdesc *f) |
1035 | { | 1030 | { |
1036 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | 1031 | if (unlikely(f->index >= ARRAY_SIZE(formats))) |
1037 | return -EINVAL; | 1032 | return -EINVAL; |
1038 | 1033 | ||
1039 | strlcpy(f->description, formats[f->index].name, | 1034 | strlcpy(f->description, formats[f->index].name, |
1040 | sizeof(f->description)); | 1035 | sizeof(f->description)); |
1041 | f->pixelformat = formats[f->index].fourcc; | 1036 | f->pixelformat = formats[f->index].fourcc; |
1042 | 1037 | ||
1043 | return 0; | 1038 | return 0; |
1044 | } | 1039 | } |
1045 | 1040 | ||
1046 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1041 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1047 | static int vidiocgmbuf(struct file *file, void *priv, | 1042 | static int vidiocgmbuf(struct file *file, void *priv, |
1048 | struct video_mbuf *mbuf) | 1043 | struct video_mbuf *mbuf) |
1049 | { | 1044 | { |
1050 | struct cx23885_fh *fh = priv; | 1045 | struct cx23885_fh *fh = priv; |
1051 | struct videobuf_queue *q; | 1046 | struct videobuf_queue *q; |
1052 | struct v4l2_requestbuffers req; | 1047 | struct v4l2_requestbuffers req; |
1053 | unsigned int i; | 1048 | unsigned int i; |
1054 | int err; | 1049 | int err; |
1055 | 1050 | ||
1056 | q = get_queue(fh); | 1051 | q = get_queue(fh); |
1057 | memset(&req, 0, sizeof(req)); | 1052 | memset(&req, 0, sizeof(req)); |
1058 | req.type = q->type; | 1053 | req.type = q->type; |
1059 | req.count = 8; | 1054 | req.count = 8; |
1060 | req.memory = V4L2_MEMORY_MMAP; | 1055 | req.memory = V4L2_MEMORY_MMAP; |
1061 | err = videobuf_reqbufs(q, &req); | 1056 | err = videobuf_reqbufs(q, &req); |
1062 | if (err < 0) | 1057 | if (err < 0) |
1063 | return err; | 1058 | return err; |
1064 | 1059 | ||
1065 | mbuf->frames = req.count; | 1060 | mbuf->frames = req.count; |
1066 | mbuf->size = 0; | 1061 | mbuf->size = 0; |
1067 | for (i = 0; i < mbuf->frames; i++) { | 1062 | for (i = 0; i < mbuf->frames; i++) { |
1068 | mbuf->offsets[i] = q->bufs[i]->boff; | 1063 | mbuf->offsets[i] = q->bufs[i]->boff; |
1069 | mbuf->size += q->bufs[i]->bsize; | 1064 | mbuf->size += q->bufs[i]->bsize; |
1070 | } | 1065 | } |
1071 | return 0; | 1066 | return 0; |
1072 | } | 1067 | } |
1073 | #endif | 1068 | #endif |
1074 | 1069 | ||
1075 | static int vidioc_reqbufs(struct file *file, void *priv, | 1070 | static int vidioc_reqbufs(struct file *file, void *priv, |
1076 | struct v4l2_requestbuffers *p) | 1071 | struct v4l2_requestbuffers *p) |
1077 | { | 1072 | { |
1078 | struct cx23885_fh *fh = priv; | 1073 | struct cx23885_fh *fh = priv; |
1079 | return videobuf_reqbufs(get_queue(fh), p); | 1074 | return videobuf_reqbufs(get_queue(fh), p); |
1080 | } | 1075 | } |
1081 | 1076 | ||
1082 | static int vidioc_querybuf(struct file *file, void *priv, | 1077 | static int vidioc_querybuf(struct file *file, void *priv, |
1083 | struct v4l2_buffer *p) | 1078 | struct v4l2_buffer *p) |
1084 | { | 1079 | { |
1085 | struct cx23885_fh *fh = priv; | 1080 | struct cx23885_fh *fh = priv; |
1086 | return videobuf_querybuf(get_queue(fh), p); | 1081 | return videobuf_querybuf(get_queue(fh), p); |
1087 | } | 1082 | } |
1088 | 1083 | ||
1089 | static int vidioc_qbuf(struct file *file, void *priv, | 1084 | static int vidioc_qbuf(struct file *file, void *priv, |
1090 | struct v4l2_buffer *p) | 1085 | struct v4l2_buffer *p) |
1091 | { | 1086 | { |
1092 | struct cx23885_fh *fh = priv; | 1087 | struct cx23885_fh *fh = priv; |
1093 | return videobuf_qbuf(get_queue(fh), p); | 1088 | return videobuf_qbuf(get_queue(fh), p); |
1094 | } | 1089 | } |
1095 | 1090 | ||
1096 | static int vidioc_dqbuf(struct file *file, void *priv, | 1091 | static int vidioc_dqbuf(struct file *file, void *priv, |
1097 | struct v4l2_buffer *p) | 1092 | struct v4l2_buffer *p) |
1098 | { | 1093 | { |
1099 | struct cx23885_fh *fh = priv; | 1094 | struct cx23885_fh *fh = priv; |
1100 | return videobuf_dqbuf(get_queue(fh), p, | 1095 | return videobuf_dqbuf(get_queue(fh), p, |
1101 | file->f_flags & O_NONBLOCK); | 1096 | file->f_flags & O_NONBLOCK); |
1102 | } | 1097 | } |
1103 | 1098 | ||
1104 | static int vidioc_streamon(struct file *file, void *priv, | 1099 | static int vidioc_streamon(struct file *file, void *priv, |
1105 | enum v4l2_buf_type i) | 1100 | enum v4l2_buf_type i) |
1106 | { | 1101 | { |
1107 | struct cx23885_fh *fh = priv; | 1102 | struct cx23885_fh *fh = priv; |
1108 | struct cx23885_dev *dev = fh->dev; | 1103 | struct cx23885_dev *dev = fh->dev; |
1109 | dprintk(1, "%s()\n", __func__); | 1104 | dprintk(1, "%s()\n", __func__); |
1110 | 1105 | ||
1111 | if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) | 1106 | if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) |
1112 | return -EINVAL; | 1107 | return -EINVAL; |
1113 | if (unlikely(i != fh->type)) | 1108 | if (unlikely(i != fh->type)) |
1114 | return -EINVAL; | 1109 | return -EINVAL; |
1115 | 1110 | ||
1116 | if (unlikely(!res_get(dev, fh, get_resource(fh)))) | 1111 | if (unlikely(!res_get(dev, fh, get_resource(fh)))) |
1117 | return -EBUSY; | 1112 | return -EBUSY; |
1118 | return videobuf_streamon(get_queue(fh)); | 1113 | return videobuf_streamon(get_queue(fh)); |
1119 | } | 1114 | } |
1120 | 1115 | ||
1121 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | 1116 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
1122 | { | 1117 | { |
1123 | struct cx23885_fh *fh = priv; | 1118 | struct cx23885_fh *fh = priv; |
1124 | struct cx23885_dev *dev = fh->dev; | 1119 | struct cx23885_dev *dev = fh->dev; |
1125 | int err, res; | 1120 | int err, res; |
1126 | dprintk(1, "%s()\n", __func__); | 1121 | dprintk(1, "%s()\n", __func__); |
1127 | 1122 | ||
1128 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1123 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1129 | return -EINVAL; | 1124 | return -EINVAL; |
1130 | if (i != fh->type) | 1125 | if (i != fh->type) |
1131 | return -EINVAL; | 1126 | return -EINVAL; |
1132 | 1127 | ||
1133 | res = get_resource(fh); | 1128 | res = get_resource(fh); |
1134 | err = videobuf_streamoff(get_queue(fh)); | 1129 | err = videobuf_streamoff(get_queue(fh)); |
1135 | if (err < 0) | 1130 | if (err < 0) |
1136 | return err; | 1131 | return err; |
1137 | res_free(dev, fh, res); | 1132 | res_free(dev, fh, res); |
1138 | return 0; | 1133 | return 0; |
1139 | } | 1134 | } |
1140 | 1135 | ||
1141 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) | 1136 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) |
1142 | { | 1137 | { |
1143 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1138 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1144 | dprintk(1, "%s()\n", __func__); | 1139 | dprintk(1, "%s()\n", __func__); |
1145 | 1140 | ||
1146 | mutex_lock(&dev->lock); | 1141 | mutex_lock(&dev->lock); |
1147 | cx23885_set_tvnorm(dev, *tvnorms); | 1142 | cx23885_set_tvnorm(dev, *tvnorms); |
1148 | mutex_unlock(&dev->lock); | 1143 | mutex_unlock(&dev->lock); |
1149 | 1144 | ||
1150 | return 0; | 1145 | return 0; |
1151 | } | 1146 | } |
1152 | 1147 | ||
1153 | static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) | 1148 | static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) |
1154 | { | 1149 | { |
1155 | static const char *iname[] = { | 1150 | static const char *iname[] = { |
1156 | [CX23885_VMUX_COMPOSITE1] = "Composite1", | 1151 | [CX23885_VMUX_COMPOSITE1] = "Composite1", |
1157 | [CX23885_VMUX_COMPOSITE2] = "Composite2", | 1152 | [CX23885_VMUX_COMPOSITE2] = "Composite2", |
1158 | [CX23885_VMUX_COMPOSITE3] = "Composite3", | 1153 | [CX23885_VMUX_COMPOSITE3] = "Composite3", |
1159 | [CX23885_VMUX_COMPOSITE4] = "Composite4", | 1154 | [CX23885_VMUX_COMPOSITE4] = "Composite4", |
1160 | [CX23885_VMUX_SVIDEO] = "S-Video", | 1155 | [CX23885_VMUX_SVIDEO] = "S-Video", |
1161 | [CX23885_VMUX_TELEVISION] = "Television", | 1156 | [CX23885_VMUX_TELEVISION] = "Television", |
1162 | [CX23885_VMUX_CABLE] = "Cable TV", | 1157 | [CX23885_VMUX_CABLE] = "Cable TV", |
1163 | [CX23885_VMUX_DVB] = "DVB", | 1158 | [CX23885_VMUX_DVB] = "DVB", |
1164 | [CX23885_VMUX_DEBUG] = "for debug only", | 1159 | [CX23885_VMUX_DEBUG] = "for debug only", |
1165 | }; | 1160 | }; |
1166 | unsigned int n; | 1161 | unsigned int n; |
1167 | dprintk(1, "%s()\n", __func__); | 1162 | dprintk(1, "%s()\n", __func__); |
1168 | 1163 | ||
1169 | n = i->index; | 1164 | n = i->index; |
1170 | if (n >= 4) | 1165 | if (n >= 4) |
1171 | return -EINVAL; | 1166 | return -EINVAL; |
1172 | 1167 | ||
1173 | if (0 == INPUT(n)->type) | 1168 | if (0 == INPUT(n)->type) |
1174 | return -EINVAL; | 1169 | return -EINVAL; |
1175 | 1170 | ||
1176 | memset(i, 0, sizeof(*i)); | 1171 | memset(i, 0, sizeof(*i)); |
1177 | i->index = n; | 1172 | i->index = n; |
1178 | i->type = V4L2_INPUT_TYPE_CAMERA; | 1173 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1179 | strcpy(i->name, iname[INPUT(n)->type]); | 1174 | strcpy(i->name, iname[INPUT(n)->type]); |
1180 | if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || | 1175 | if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || |
1181 | (CX23885_VMUX_CABLE == INPUT(n)->type)) | 1176 | (CX23885_VMUX_CABLE == INPUT(n)->type)) |
1182 | i->type = V4L2_INPUT_TYPE_TUNER; | 1177 | i->type = V4L2_INPUT_TYPE_TUNER; |
1183 | i->std = CX23885_NORMS; | 1178 | i->std = CX23885_NORMS; |
1184 | return 0; | 1179 | return 0; |
1185 | } | 1180 | } |
1186 | 1181 | ||
1187 | static int vidioc_enum_input(struct file *file, void *priv, | 1182 | static int vidioc_enum_input(struct file *file, void *priv, |
1188 | struct v4l2_input *i) | 1183 | struct v4l2_input *i) |
1189 | { | 1184 | { |
1190 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1185 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1191 | dprintk(1, "%s()\n", __func__); | 1186 | dprintk(1, "%s()\n", __func__); |
1192 | return cx23885_enum_input(dev, i); | 1187 | return cx23885_enum_input(dev, i); |
1193 | } | 1188 | } |
1194 | 1189 | ||
1195 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | 1190 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) |
1196 | { | 1191 | { |
1197 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1192 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1198 | 1193 | ||
1199 | *i = dev->input; | 1194 | *i = dev->input; |
1200 | dprintk(1, "%s() returns %d\n", __func__, *i); | 1195 | dprintk(1, "%s() returns %d\n", __func__, *i); |
1201 | return 0; | 1196 | return 0; |
1202 | } | 1197 | } |
1203 | 1198 | ||
1204 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | 1199 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) |
1205 | { | 1200 | { |
1206 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1201 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1207 | 1202 | ||
1208 | dprintk(1, "%s(%d)\n", __func__, i); | 1203 | dprintk(1, "%s(%d)\n", __func__, i); |
1209 | 1204 | ||
1210 | if (i >= 4) { | 1205 | if (i >= 4) { |
1211 | dprintk(1, "%s() -EINVAL\n", __func__); | 1206 | dprintk(1, "%s() -EINVAL\n", __func__); |
1212 | return -EINVAL; | 1207 | return -EINVAL; |
1213 | } | 1208 | } |
1214 | 1209 | ||
1215 | mutex_lock(&dev->lock); | 1210 | mutex_lock(&dev->lock); |
1216 | cx23885_video_mux(dev, i); | 1211 | cx23885_video_mux(dev, i); |
1217 | mutex_unlock(&dev->lock); | 1212 | mutex_unlock(&dev->lock); |
1218 | return 0; | 1213 | return 0; |
1219 | } | 1214 | } |
1220 | 1215 | ||
1221 | static int vidioc_queryctrl(struct file *file, void *priv, | 1216 | static int vidioc_queryctrl(struct file *file, void *priv, |
1222 | struct v4l2_queryctrl *qctrl) | 1217 | struct v4l2_queryctrl *qctrl) |
1223 | { | 1218 | { |
1224 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | 1219 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); |
1225 | if (unlikely(qctrl->id == 0)) | 1220 | if (unlikely(qctrl->id == 0)) |
1226 | return -EINVAL; | 1221 | return -EINVAL; |
1227 | return cx23885_ctrl_query(qctrl); | 1222 | return cx23885_ctrl_query(qctrl); |
1228 | } | 1223 | } |
1229 | 1224 | ||
1230 | static int vidioc_g_ctrl(struct file *file, void *priv, | 1225 | static int vidioc_g_ctrl(struct file *file, void *priv, |
1231 | struct v4l2_control *ctl) | 1226 | struct v4l2_control *ctl) |
1232 | { | 1227 | { |
1233 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1228 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1234 | 1229 | ||
1235 | return cx23885_get_control(dev, ctl); | 1230 | return cx23885_get_control(dev, ctl); |
1236 | } | 1231 | } |
1237 | 1232 | ||
1238 | static int vidioc_s_ctrl(struct file *file, void *priv, | 1233 | static int vidioc_s_ctrl(struct file *file, void *priv, |
1239 | struct v4l2_control *ctl) | 1234 | struct v4l2_control *ctl) |
1240 | { | 1235 | { |
1241 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1236 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1242 | 1237 | ||
1243 | return cx23885_set_control(dev, ctl); | 1238 | return cx23885_set_control(dev, ctl); |
1244 | } | 1239 | } |
1245 | 1240 | ||
1246 | static int vidioc_g_tuner(struct file *file, void *priv, | 1241 | static int vidioc_g_tuner(struct file *file, void *priv, |
1247 | struct v4l2_tuner *t) | 1242 | struct v4l2_tuner *t) |
1248 | { | 1243 | { |
1249 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1244 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1250 | 1245 | ||
1251 | if (unlikely(UNSET == dev->tuner_type)) | 1246 | if (unlikely(UNSET == dev->tuner_type)) |
1252 | return -EINVAL; | 1247 | return -EINVAL; |
1253 | if (0 != t->index) | 1248 | if (0 != t->index) |
1254 | return -EINVAL; | 1249 | return -EINVAL; |
1255 | 1250 | ||
1256 | strcpy(t->name, "Television"); | 1251 | strcpy(t->name, "Television"); |
1257 | t->type = V4L2_TUNER_ANALOG_TV; | 1252 | t->type = V4L2_TUNER_ANALOG_TV; |
1258 | t->capability = V4L2_TUNER_CAP_NORM; | 1253 | t->capability = V4L2_TUNER_CAP_NORM; |
1259 | t->rangehigh = 0xffffffffUL; | 1254 | t->rangehigh = 0xffffffffUL; |
1260 | t->signal = 0xffff ; /* LOCKED */ | 1255 | t->signal = 0xffff ; /* LOCKED */ |
1261 | return 0; | 1256 | return 0; |
1262 | } | 1257 | } |
1263 | 1258 | ||
1264 | static int vidioc_s_tuner(struct file *file, void *priv, | 1259 | static int vidioc_s_tuner(struct file *file, void *priv, |
1265 | struct v4l2_tuner *t) | 1260 | struct v4l2_tuner *t) |
1266 | { | 1261 | { |
1267 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; | 1262 | struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; |
1268 | 1263 | ||
1269 | if (UNSET == dev->tuner_type) | 1264 | if (UNSET == dev->tuner_type) |
1270 | return -EINVAL; | 1265 | return -EINVAL; |
1271 | if (0 != t->index) | 1266 | if (0 != t->index) |
1272 | return -EINVAL; | 1267 | return -EINVAL; |
1273 | return 0; | 1268 | return 0; |
1274 | } | 1269 | } |
1275 | 1270 | ||
1276 | static int vidioc_g_frequency(struct file *file, void *priv, | 1271 | static int vidioc_g_frequency(struct file *file, void *priv, |
1277 | struct v4l2_frequency *f) | 1272 | struct v4l2_frequency *f) |
1278 | { | 1273 | { |
1279 | struct cx23885_fh *fh = priv; | 1274 | struct cx23885_fh *fh = priv; |
1280 | struct cx23885_dev *dev = fh->dev; | 1275 | struct cx23885_dev *dev = fh->dev; |
1281 | 1276 | ||
1282 | if (unlikely(UNSET == dev->tuner_type)) | 1277 | if (unlikely(UNSET == dev->tuner_type)) |
1283 | return -EINVAL; | 1278 | return -EINVAL; |
1284 | 1279 | ||
1285 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | 1280 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ |
1286 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 1281 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; |
1287 | f->frequency = dev->freq; | 1282 | f->frequency = dev->freq; |
1288 | 1283 | ||
1289 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); | 1284 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); |
1290 | 1285 | ||
1291 | return 0; | 1286 | return 0; |
1292 | } | 1287 | } |
1293 | 1288 | ||
1294 | static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) | 1289 | static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) |
1295 | { | 1290 | { |
1296 | if (unlikely(UNSET == dev->tuner_type)) | 1291 | if (unlikely(UNSET == dev->tuner_type)) |
1297 | return -EINVAL; | 1292 | return -EINVAL; |
1298 | if (unlikely(f->tuner != 0)) | 1293 | if (unlikely(f->tuner != 0)) |
1299 | return -EINVAL; | 1294 | return -EINVAL; |
1300 | 1295 | ||
1301 | mutex_lock(&dev->lock); | 1296 | mutex_lock(&dev->lock); |
1302 | dev->freq = f->frequency; | 1297 | dev->freq = f->frequency; |
1303 | 1298 | ||
1304 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); | 1299 | cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); |
1305 | 1300 | ||
1306 | /* When changing channels it is required to reset TVAUDIO */ | 1301 | /* When changing channels it is required to reset TVAUDIO */ |
1307 | msleep(10); | 1302 | msleep(10); |
1308 | 1303 | ||
1309 | mutex_unlock(&dev->lock); | 1304 | mutex_unlock(&dev->lock); |
1310 | 1305 | ||
1311 | return 0; | 1306 | return 0; |
1312 | } | 1307 | } |
1313 | 1308 | ||
1314 | static int vidioc_s_frequency(struct file *file, void *priv, | 1309 | static int vidioc_s_frequency(struct file *file, void *priv, |
1315 | struct v4l2_frequency *f) | 1310 | struct v4l2_frequency *f) |
1316 | { | 1311 | { |
1317 | struct cx23885_fh *fh = priv; | 1312 | struct cx23885_fh *fh = priv; |
1318 | struct cx23885_dev *dev = fh->dev; | 1313 | struct cx23885_dev *dev = fh->dev; |
1319 | 1314 | ||
1320 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) | 1315 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) |
1321 | return -EINVAL; | 1316 | return -EINVAL; |
1322 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | 1317 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) |
1323 | return -EINVAL; | 1318 | return -EINVAL; |
1324 | 1319 | ||
1325 | return | 1320 | return |
1326 | cx23885_set_freq(dev, f); | 1321 | cx23885_set_freq(dev, f); |
1327 | } | 1322 | } |
1328 | 1323 | ||
1329 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1324 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1330 | static int vidioc_g_register(struct file *file, void *fh, | 1325 | static int vidioc_g_register(struct file *file, void *fh, |
1331 | struct v4l2_dbg_register *reg) | 1326 | struct v4l2_dbg_register *reg) |
1332 | { | 1327 | { |
1333 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | 1328 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; |
1334 | 1329 | ||
1335 | if (!v4l2_chip_match_host(®->match)) | 1330 | if (!v4l2_chip_match_host(®->match)) |
1336 | return -EINVAL; | 1331 | return -EINVAL; |
1337 | 1332 | ||
1338 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); | 1333 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); |
1339 | 1334 | ||
1340 | return 0; | 1335 | return 0; |
1341 | } | 1336 | } |
1342 | 1337 | ||
1343 | static int vidioc_s_register(struct file *file, void *fh, | 1338 | static int vidioc_s_register(struct file *file, void *fh, |
1344 | struct v4l2_dbg_register *reg) | 1339 | struct v4l2_dbg_register *reg) |
1345 | { | 1340 | { |
1346 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | 1341 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; |
1347 | 1342 | ||
1348 | if (!v4l2_chip_match_host(®->match)) | 1343 | if (!v4l2_chip_match_host(®->match)) |
1349 | return -EINVAL; | 1344 | return -EINVAL; |
1350 | 1345 | ||
1351 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); | 1346 | cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); |
1352 | 1347 | ||
1353 | return 0; | 1348 | return 0; |
1354 | } | 1349 | } |
1355 | #endif | 1350 | #endif |
1356 | 1351 | ||
1357 | /* ----------------------------------------------------------- */ | 1352 | /* ----------------------------------------------------------- */ |
1358 | 1353 | ||
1359 | static void cx23885_vid_timeout(unsigned long data) | 1354 | static void cx23885_vid_timeout(unsigned long data) |
1360 | { | 1355 | { |
1361 | struct cx23885_dev *dev = (struct cx23885_dev *)data; | 1356 | struct cx23885_dev *dev = (struct cx23885_dev *)data; |
1362 | struct cx23885_dmaqueue *q = &dev->vidq; | 1357 | struct cx23885_dmaqueue *q = &dev->vidq; |
1363 | struct cx23885_buffer *buf; | 1358 | struct cx23885_buffer *buf; |
1364 | unsigned long flags; | 1359 | unsigned long flags; |
1365 | 1360 | ||
1366 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); | 1361 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); |
1367 | 1362 | ||
1368 | cx_clear(VID_A_DMA_CTL, 0x11); | 1363 | cx_clear(VID_A_DMA_CTL, 0x11); |
1369 | 1364 | ||
1370 | spin_lock_irqsave(&dev->slock, flags); | 1365 | spin_lock_irqsave(&dev->slock, flags); |
1371 | while (!list_empty(&q->active)) { | 1366 | while (!list_empty(&q->active)) { |
1372 | buf = list_entry(q->active.next, | 1367 | buf = list_entry(q->active.next, |
1373 | struct cx23885_buffer, vb.queue); | 1368 | struct cx23885_buffer, vb.queue); |
1374 | list_del(&buf->vb.queue); | 1369 | list_del(&buf->vb.queue); |
1375 | buf->vb.state = VIDEOBUF_ERROR; | 1370 | buf->vb.state = VIDEOBUF_ERROR; |
1376 | wake_up(&buf->vb.done); | 1371 | wake_up(&buf->vb.done); |
1377 | printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", | 1372 | printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", |
1378 | dev->name, buf, buf->vb.i, | 1373 | dev->name, buf, buf->vb.i, |
1379 | (unsigned long)buf->risc.dma); | 1374 | (unsigned long)buf->risc.dma); |
1380 | } | 1375 | } |
1381 | cx23885_restart_video_queue(dev, q); | 1376 | cx23885_restart_video_queue(dev, q); |
1382 | spin_unlock_irqrestore(&dev->slock, flags); | 1377 | spin_unlock_irqrestore(&dev->slock, flags); |
1383 | } | 1378 | } |
1384 | 1379 | ||
1385 | int cx23885_video_irq(struct cx23885_dev *dev, u32 status) | 1380 | int cx23885_video_irq(struct cx23885_dev *dev, u32 status) |
1386 | { | 1381 | { |
1387 | u32 mask, count; | 1382 | u32 mask, count; |
1388 | int handled = 0; | 1383 | int handled = 0; |
1389 | 1384 | ||
1390 | mask = cx_read(VID_A_INT_MSK); | 1385 | mask = cx_read(VID_A_INT_MSK); |
1391 | if (0 == (status & mask)) | 1386 | if (0 == (status & mask)) |
1392 | return handled; | 1387 | return handled; |
1393 | cx_write(VID_A_INT_STAT, status); | 1388 | cx_write(VID_A_INT_STAT, status); |
1394 | 1389 | ||
1395 | dprintk(2, "%s() status = 0x%08x\n", __func__, status); | 1390 | dprintk(2, "%s() status = 0x%08x\n", __func__, status); |
1396 | /* risc op code error */ | 1391 | /* risc op code error */ |
1397 | if (status & (1 << 16)) { | 1392 | if (status & (1 << 16)) { |
1398 | printk(KERN_WARNING "%s/0: video risc op code error\n", | 1393 | printk(KERN_WARNING "%s/0: video risc op code error\n", |
1399 | dev->name); | 1394 | dev->name); |
1400 | cx_clear(VID_A_DMA_CTL, 0x11); | 1395 | cx_clear(VID_A_DMA_CTL, 0x11); |
1401 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); | 1396 | cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); |
1402 | } | 1397 | } |
1403 | 1398 | ||
1404 | /* risc1 y */ | 1399 | /* risc1 y */ |
1405 | if (status & 0x01) { | 1400 | if (status & 0x01) { |
1406 | spin_lock(&dev->slock); | 1401 | spin_lock(&dev->slock); |
1407 | count = cx_read(VID_A_GPCNT); | 1402 | count = cx_read(VID_A_GPCNT); |
1408 | cx23885_video_wakeup(dev, &dev->vidq, count); | 1403 | cx23885_video_wakeup(dev, &dev->vidq, count); |
1409 | spin_unlock(&dev->slock); | 1404 | spin_unlock(&dev->slock); |
1410 | handled++; | 1405 | handled++; |
1411 | } | 1406 | } |
1412 | /* risc2 y */ | 1407 | /* risc2 y */ |
1413 | if (status & 0x10) { | 1408 | if (status & 0x10) { |
1414 | dprintk(2, "stopper video\n"); | 1409 | dprintk(2, "stopper video\n"); |
1415 | spin_lock(&dev->slock); | 1410 | spin_lock(&dev->slock); |
1416 | cx23885_restart_video_queue(dev, &dev->vidq); | 1411 | cx23885_restart_video_queue(dev, &dev->vidq); |
1417 | spin_unlock(&dev->slock); | 1412 | spin_unlock(&dev->slock); |
1418 | handled++; | 1413 | handled++; |
1419 | } | 1414 | } |
1420 | 1415 | ||
1421 | return handled; | 1416 | return handled; |
1422 | } | 1417 | } |
1423 | 1418 | ||
1424 | /* ----------------------------------------------------------- */ | 1419 | /* ----------------------------------------------------------- */ |
1425 | /* exported stuff */ | 1420 | /* exported stuff */ |
1426 | 1421 | ||
1427 | static const struct v4l2_file_operations video_fops = { | 1422 | static const struct v4l2_file_operations video_fops = { |
1428 | .owner = THIS_MODULE, | 1423 | .owner = THIS_MODULE, |
1429 | .open = video_open, | 1424 | .open = video_open, |
1430 | .release = video_release, | 1425 | .release = video_release, |
1431 | .read = video_read, | 1426 | .read = video_read, |
1432 | .poll = video_poll, | 1427 | .poll = video_poll, |
1433 | .mmap = video_mmap, | 1428 | .mmap = video_mmap, |
1434 | .ioctl = video_ioctl2, | 1429 | .ioctl = video_ioctl2, |
1435 | }; | 1430 | }; |
1436 | 1431 | ||
1437 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | 1432 | static const struct v4l2_ioctl_ops video_ioctl_ops = { |
1438 | .vidioc_querycap = vidioc_querycap, | 1433 | .vidioc_querycap = vidioc_querycap, |
1439 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | 1434 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1440 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 1435 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
1441 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | 1436 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, |
1442 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | 1437 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, |
1443 | .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, | 1438 | .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, |
1444 | .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, | 1439 | .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, |
1445 | .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, | 1440 | .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, |
1446 | .vidioc_reqbufs = vidioc_reqbufs, | 1441 | .vidioc_reqbufs = vidioc_reqbufs, |
1447 | .vidioc_querybuf = vidioc_querybuf, | 1442 | .vidioc_querybuf = vidioc_querybuf, |
1448 | .vidioc_qbuf = vidioc_qbuf, | 1443 | .vidioc_qbuf = vidioc_qbuf, |
1449 | .vidioc_dqbuf = vidioc_dqbuf, | 1444 | .vidioc_dqbuf = vidioc_dqbuf, |
1450 | .vidioc_s_std = vidioc_s_std, | 1445 | .vidioc_s_std = vidioc_s_std, |
1451 | .vidioc_enum_input = vidioc_enum_input, | 1446 | .vidioc_enum_input = vidioc_enum_input, |
1452 | .vidioc_g_input = vidioc_g_input, | 1447 | .vidioc_g_input = vidioc_g_input, |
1453 | .vidioc_s_input = vidioc_s_input, | 1448 | .vidioc_s_input = vidioc_s_input, |
1454 | .vidioc_queryctrl = vidioc_queryctrl, | 1449 | .vidioc_queryctrl = vidioc_queryctrl, |
1455 | .vidioc_g_ctrl = vidioc_g_ctrl, | 1450 | .vidioc_g_ctrl = vidioc_g_ctrl, |
1456 | .vidioc_s_ctrl = vidioc_s_ctrl, | 1451 | .vidioc_s_ctrl = vidioc_s_ctrl, |
1457 | .vidioc_streamon = vidioc_streamon, | 1452 | .vidioc_streamon = vidioc_streamon, |
1458 | .vidioc_streamoff = vidioc_streamoff, | 1453 | .vidioc_streamoff = vidioc_streamoff, |
1459 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1454 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1460 | .vidiocgmbuf = vidiocgmbuf, | 1455 | .vidiocgmbuf = vidiocgmbuf, |
1461 | #endif | 1456 | #endif |
1462 | .vidioc_g_tuner = vidioc_g_tuner, | 1457 | .vidioc_g_tuner = vidioc_g_tuner, |
1463 | .vidioc_s_tuner = vidioc_s_tuner, | 1458 | .vidioc_s_tuner = vidioc_s_tuner, |
1464 | .vidioc_g_frequency = vidioc_g_frequency, | 1459 | .vidioc_g_frequency = vidioc_g_frequency, |
1465 | .vidioc_s_frequency = vidioc_s_frequency, | 1460 | .vidioc_s_frequency = vidioc_s_frequency, |
1466 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1461 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1467 | .vidioc_g_register = vidioc_g_register, | 1462 | .vidioc_g_register = vidioc_g_register, |
1468 | .vidioc_s_register = vidioc_s_register, | 1463 | .vidioc_s_register = vidioc_s_register, |
1469 | #endif | 1464 | #endif |
1470 | }; | 1465 | }; |
1471 | 1466 | ||
1472 | static struct video_device cx23885_vbi_template; | 1467 | static struct video_device cx23885_vbi_template; |
1473 | static struct video_device cx23885_video_template = { | 1468 | static struct video_device cx23885_video_template = { |
1474 | .name = "cx23885-video", | 1469 | .name = "cx23885-video", |
1475 | .fops = &video_fops, | 1470 | .fops = &video_fops, |
1476 | .minor = -1, | 1471 | .minor = -1, |
1477 | .ioctl_ops = &video_ioctl_ops, | 1472 | .ioctl_ops = &video_ioctl_ops, |
1478 | .tvnorms = CX23885_NORMS, | 1473 | .tvnorms = CX23885_NORMS, |
1479 | .current_norm = V4L2_STD_NTSC_M, | 1474 | .current_norm = V4L2_STD_NTSC_M, |
1480 | }; | 1475 | }; |
1481 | 1476 | ||
1482 | static const struct v4l2_file_operations radio_fops = { | 1477 | static const struct v4l2_file_operations radio_fops = { |
1483 | .owner = THIS_MODULE, | 1478 | .owner = THIS_MODULE, |
1484 | .open = video_open, | 1479 | .open = video_open, |
1485 | .release = video_release, | 1480 | .release = video_release, |
1486 | .ioctl = video_ioctl2, | 1481 | .ioctl = video_ioctl2, |
1487 | }; | 1482 | }; |
1488 | 1483 | ||
1489 | 1484 | ||
1490 | void cx23885_video_unregister(struct cx23885_dev *dev) | 1485 | void cx23885_video_unregister(struct cx23885_dev *dev) |
1491 | { | 1486 | { |
1492 | dprintk(1, "%s()\n", __func__); | 1487 | dprintk(1, "%s()\n", __func__); |
1493 | cx_clear(PCI_INT_MSK, 1); | 1488 | cx_clear(PCI_INT_MSK, 1); |
1494 | 1489 | ||
1495 | if (dev->video_dev) { | 1490 | if (dev->video_dev) { |
1496 | if (-1 != dev->video_dev->minor) | 1491 | if (-1 != dev->video_dev->minor) |
1497 | video_unregister_device(dev->video_dev); | 1492 | video_unregister_device(dev->video_dev); |
1498 | else | 1493 | else |
1499 | video_device_release(dev->video_dev); | 1494 | video_device_release(dev->video_dev); |
1500 | dev->video_dev = NULL; | 1495 | dev->video_dev = NULL; |
1501 | 1496 | ||
1502 | btcx_riscmem_free(dev->pci, &dev->vidq.stopper); | 1497 | btcx_riscmem_free(dev->pci, &dev->vidq.stopper); |
1503 | } | 1498 | } |
1504 | } | 1499 | } |
1505 | 1500 | ||
1506 | int cx23885_video_register(struct cx23885_dev *dev) | 1501 | int cx23885_video_register(struct cx23885_dev *dev) |
1507 | { | 1502 | { |
1508 | int err; | 1503 | int err; |
1509 | 1504 | ||
1510 | dprintk(1, "%s()\n", __func__); | 1505 | dprintk(1, "%s()\n", __func__); |
1511 | spin_lock_init(&dev->slock); | 1506 | spin_lock_init(&dev->slock); |
1512 | 1507 | ||
1513 | /* Initialize VBI template */ | 1508 | /* Initialize VBI template */ |
1514 | memcpy(&cx23885_vbi_template, &cx23885_video_template, | 1509 | memcpy(&cx23885_vbi_template, &cx23885_video_template, |
1515 | sizeof(cx23885_vbi_template)); | 1510 | sizeof(cx23885_vbi_template)); |
1516 | strcpy(cx23885_vbi_template.name, "cx23885-vbi"); | 1511 | strcpy(cx23885_vbi_template.name, "cx23885-vbi"); |
1517 | 1512 | ||
1518 | dev->tvnorm = cx23885_video_template.current_norm; | 1513 | dev->tvnorm = cx23885_video_template.current_norm; |
1519 | 1514 | ||
1520 | /* init video dma queues */ | 1515 | /* init video dma queues */ |
1521 | INIT_LIST_HEAD(&dev->vidq.active); | 1516 | INIT_LIST_HEAD(&dev->vidq.active); |
1522 | INIT_LIST_HEAD(&dev->vidq.queued); | 1517 | INIT_LIST_HEAD(&dev->vidq.queued); |
1523 | dev->vidq.timeout.function = cx23885_vid_timeout; | 1518 | dev->vidq.timeout.function = cx23885_vid_timeout; |
1524 | dev->vidq.timeout.data = (unsigned long)dev; | 1519 | dev->vidq.timeout.data = (unsigned long)dev; |
1525 | init_timer(&dev->vidq.timeout); | 1520 | init_timer(&dev->vidq.timeout); |
1526 | cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, | 1521 | cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, |
1527 | VID_A_DMA_CTL, 0x11, 0x00); | 1522 | VID_A_DMA_CTL, 0x11, 0x00); |
1528 | 1523 | ||
1529 | /* Don't enable VBI yet */ | 1524 | /* Don't enable VBI yet */ |
1530 | cx_set(PCI_INT_MSK, 1); | 1525 | cx_set(PCI_INT_MSK, 1); |
1531 | 1526 | ||
1532 | 1527 | ||
1533 | /* register v4l devices */ | 1528 | /* register v4l devices */ |
1534 | dev->video_dev = cx23885_vdev_init(dev, dev->pci, | 1529 | dev->video_dev = cx23885_vdev_init(dev, dev->pci, |
1535 | &cx23885_video_template, "video"); | 1530 | &cx23885_video_template, "video"); |
1536 | err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, | 1531 | err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, |
1537 | video_nr[dev->nr]); | 1532 | video_nr[dev->nr]); |
1538 | if (err < 0) { | 1533 | if (err < 0) { |
1539 | printk(KERN_INFO "%s: can't register video device\n", | 1534 | printk(KERN_INFO "%s: can't register video device\n", |
1540 | dev->name); | 1535 | dev->name); |
1541 | goto fail_unreg; | 1536 | goto fail_unreg; |
1542 | } | 1537 | } |
1543 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", | 1538 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", |
1544 | dev->name, dev->video_dev->num); | 1539 | dev->name, dev->video_dev->num); |
1545 | /* initial device configuration */ | 1540 | /* initial device configuration */ |
1546 | mutex_lock(&dev->lock); | 1541 | mutex_lock(&dev->lock); |
1547 | cx23885_set_tvnorm(dev, dev->tvnorm); | 1542 | cx23885_set_tvnorm(dev, dev->tvnorm); |
1548 | init_controls(dev); | 1543 | init_controls(dev); |
1549 | cx23885_video_mux(dev, 0); | 1544 | cx23885_video_mux(dev, 0); |
1550 | mutex_unlock(&dev->lock); | 1545 | mutex_unlock(&dev->lock); |
1551 | 1546 | ||
1552 | return 0; | 1547 | return 0; |
1553 | 1548 | ||
1554 | fail_unreg: | 1549 | fail_unreg: |
1555 | cx23885_video_unregister(dev); | 1550 | cx23885_video_unregister(dev); |
1556 | return err; | 1551 | return err; |
1557 | } | 1552 | } |
1558 | 1553 | ||
1559 | 1554 |
drivers/media/video/cx88/cx88-video.c
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * device driver for Conexant 2388x based TV cards | 3 | * device driver for Conexant 2388x based TV cards |
4 | * video4linux video interface | 4 | * video4linux video interface |
5 | * | 5 | * |
6 | * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | 6 | * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
7 | * | 7 | * |
8 | * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> | 8 | * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> |
9 | * - Multituner support | 9 | * - Multituner support |
10 | * - video_ioctl2 conversion | 10 | * - video_ioctl2 conversion |
11 | * - PAL/M fixes | 11 | * - PAL/M fixes |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
15 | * the Free Software Foundation; either version 2 of the License, or | 15 | * the Free Software Foundation; either version 2 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | * | 22 | * |
23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/kmod.h> | 31 | #include <linux/kmod.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
38 | #include <asm/div64.h> | 38 | #include <asm/div64.h> |
39 | 39 | ||
40 | #include "cx88.h" | 40 | #include "cx88.h" |
41 | #include <media/v4l2-common.h> | 41 | #include <media/v4l2-common.h> |
42 | #include <media/v4l2-ioctl.h> | 42 | #include <media/v4l2-ioctl.h> |
43 | 43 | ||
44 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
45 | /* Include V4L1 specific functions. Should be removed soon */ | ||
46 | #include <linux/videodev.h> | ||
47 | #endif | ||
48 | |||
49 | MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); | 44 | MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); |
50 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 45 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
51 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
52 | 47 | ||
53 | /* ------------------------------------------------------------------ */ | 48 | /* ------------------------------------------------------------------ */ |
54 | 49 | ||
55 | static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | 50 | static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; |
56 | static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | 51 | static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; |
57 | static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | 52 | static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; |
58 | 53 | ||
59 | module_param_array(video_nr, int, NULL, 0444); | 54 | module_param_array(video_nr, int, NULL, 0444); |
60 | module_param_array(vbi_nr, int, NULL, 0444); | 55 | module_param_array(vbi_nr, int, NULL, 0444); |
61 | module_param_array(radio_nr, int, NULL, 0444); | 56 | module_param_array(radio_nr, int, NULL, 0444); |
62 | 57 | ||
63 | MODULE_PARM_DESC(video_nr,"video device numbers"); | 58 | MODULE_PARM_DESC(video_nr,"video device numbers"); |
64 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); | 59 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); |
65 | MODULE_PARM_DESC(radio_nr,"radio device numbers"); | 60 | MODULE_PARM_DESC(radio_nr,"radio device numbers"); |
66 | 61 | ||
67 | static unsigned int video_debug; | 62 | static unsigned int video_debug; |
68 | module_param(video_debug,int,0644); | 63 | module_param(video_debug,int,0644); |
69 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); | 64 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); |
70 | 65 | ||
71 | static unsigned int irq_debug; | 66 | static unsigned int irq_debug; |
72 | module_param(irq_debug,int,0644); | 67 | module_param(irq_debug,int,0644); |
73 | MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); | 68 | MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); |
74 | 69 | ||
75 | static unsigned int vid_limit = 16; | 70 | static unsigned int vid_limit = 16; |
76 | module_param(vid_limit,int,0644); | 71 | module_param(vid_limit,int,0644); |
77 | MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); | 72 | MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); |
78 | 73 | ||
79 | #define dprintk(level,fmt, arg...) if (video_debug >= level) \ | 74 | #define dprintk(level,fmt, arg...) if (video_debug >= level) \ |
80 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) | 75 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) |
81 | 76 | ||
82 | /* ------------------------------------------------------------------ */ | 77 | /* ------------------------------------------------------------------ */ |
83 | 78 | ||
84 | static LIST_HEAD(cx8800_devlist); | 79 | static LIST_HEAD(cx8800_devlist); |
85 | 80 | ||
86 | /* ------------------------------------------------------------------- */ | 81 | /* ------------------------------------------------------------------- */ |
87 | /* static data */ | 82 | /* static data */ |
88 | 83 | ||
89 | static struct cx8800_fmt formats[] = { | 84 | static struct cx8800_fmt formats[] = { |
90 | { | 85 | { |
91 | .name = "8 bpp, gray", | 86 | .name = "8 bpp, gray", |
92 | .fourcc = V4L2_PIX_FMT_GREY, | 87 | .fourcc = V4L2_PIX_FMT_GREY, |
93 | .cxformat = ColorFormatY8, | 88 | .cxformat = ColorFormatY8, |
94 | .depth = 8, | 89 | .depth = 8, |
95 | .flags = FORMAT_FLAGS_PACKED, | 90 | .flags = FORMAT_FLAGS_PACKED, |
96 | },{ | 91 | },{ |
97 | .name = "15 bpp RGB, le", | 92 | .name = "15 bpp RGB, le", |
98 | .fourcc = V4L2_PIX_FMT_RGB555, | 93 | .fourcc = V4L2_PIX_FMT_RGB555, |
99 | .cxformat = ColorFormatRGB15, | 94 | .cxformat = ColorFormatRGB15, |
100 | .depth = 16, | 95 | .depth = 16, |
101 | .flags = FORMAT_FLAGS_PACKED, | 96 | .flags = FORMAT_FLAGS_PACKED, |
102 | },{ | 97 | },{ |
103 | .name = "15 bpp RGB, be", | 98 | .name = "15 bpp RGB, be", |
104 | .fourcc = V4L2_PIX_FMT_RGB555X, | 99 | .fourcc = V4L2_PIX_FMT_RGB555X, |
105 | .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, | 100 | .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, |
106 | .depth = 16, | 101 | .depth = 16, |
107 | .flags = FORMAT_FLAGS_PACKED, | 102 | .flags = FORMAT_FLAGS_PACKED, |
108 | },{ | 103 | },{ |
109 | .name = "16 bpp RGB, le", | 104 | .name = "16 bpp RGB, le", |
110 | .fourcc = V4L2_PIX_FMT_RGB565, | 105 | .fourcc = V4L2_PIX_FMT_RGB565, |
111 | .cxformat = ColorFormatRGB16, | 106 | .cxformat = ColorFormatRGB16, |
112 | .depth = 16, | 107 | .depth = 16, |
113 | .flags = FORMAT_FLAGS_PACKED, | 108 | .flags = FORMAT_FLAGS_PACKED, |
114 | },{ | 109 | },{ |
115 | .name = "16 bpp RGB, be", | 110 | .name = "16 bpp RGB, be", |
116 | .fourcc = V4L2_PIX_FMT_RGB565X, | 111 | .fourcc = V4L2_PIX_FMT_RGB565X, |
117 | .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, | 112 | .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, |
118 | .depth = 16, | 113 | .depth = 16, |
119 | .flags = FORMAT_FLAGS_PACKED, | 114 | .flags = FORMAT_FLAGS_PACKED, |
120 | },{ | 115 | },{ |
121 | .name = "24 bpp RGB, le", | 116 | .name = "24 bpp RGB, le", |
122 | .fourcc = V4L2_PIX_FMT_BGR24, | 117 | .fourcc = V4L2_PIX_FMT_BGR24, |
123 | .cxformat = ColorFormatRGB24, | 118 | .cxformat = ColorFormatRGB24, |
124 | .depth = 24, | 119 | .depth = 24, |
125 | .flags = FORMAT_FLAGS_PACKED, | 120 | .flags = FORMAT_FLAGS_PACKED, |
126 | },{ | 121 | },{ |
127 | .name = "32 bpp RGB, le", | 122 | .name = "32 bpp RGB, le", |
128 | .fourcc = V4L2_PIX_FMT_BGR32, | 123 | .fourcc = V4L2_PIX_FMT_BGR32, |
129 | .cxformat = ColorFormatRGB32, | 124 | .cxformat = ColorFormatRGB32, |
130 | .depth = 32, | 125 | .depth = 32, |
131 | .flags = FORMAT_FLAGS_PACKED, | 126 | .flags = FORMAT_FLAGS_PACKED, |
132 | },{ | 127 | },{ |
133 | .name = "32 bpp RGB, be", | 128 | .name = "32 bpp RGB, be", |
134 | .fourcc = V4L2_PIX_FMT_RGB32, | 129 | .fourcc = V4L2_PIX_FMT_RGB32, |
135 | .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, | 130 | .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, |
136 | .depth = 32, | 131 | .depth = 32, |
137 | .flags = FORMAT_FLAGS_PACKED, | 132 | .flags = FORMAT_FLAGS_PACKED, |
138 | },{ | 133 | },{ |
139 | .name = "4:2:2, packed, YUYV", | 134 | .name = "4:2:2, packed, YUYV", |
140 | .fourcc = V4L2_PIX_FMT_YUYV, | 135 | .fourcc = V4L2_PIX_FMT_YUYV, |
141 | .cxformat = ColorFormatYUY2, | 136 | .cxformat = ColorFormatYUY2, |
142 | .depth = 16, | 137 | .depth = 16, |
143 | .flags = FORMAT_FLAGS_PACKED, | 138 | .flags = FORMAT_FLAGS_PACKED, |
144 | },{ | 139 | },{ |
145 | .name = "4:2:2, packed, UYVY", | 140 | .name = "4:2:2, packed, UYVY", |
146 | .fourcc = V4L2_PIX_FMT_UYVY, | 141 | .fourcc = V4L2_PIX_FMT_UYVY, |
147 | .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, | 142 | .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, |
148 | .depth = 16, | 143 | .depth = 16, |
149 | .flags = FORMAT_FLAGS_PACKED, | 144 | .flags = FORMAT_FLAGS_PACKED, |
150 | }, | 145 | }, |
151 | }; | 146 | }; |
152 | 147 | ||
153 | static struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) | 148 | static struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) |
154 | { | 149 | { |
155 | unsigned int i; | 150 | unsigned int i; |
156 | 151 | ||
157 | for (i = 0; i < ARRAY_SIZE(formats); i++) | 152 | for (i = 0; i < ARRAY_SIZE(formats); i++) |
158 | if (formats[i].fourcc == fourcc) | 153 | if (formats[i].fourcc == fourcc) |
159 | return formats+i; | 154 | return formats+i; |
160 | return NULL; | 155 | return NULL; |
161 | } | 156 | } |
162 | 157 | ||
163 | /* ------------------------------------------------------------------- */ | 158 | /* ------------------------------------------------------------------- */ |
164 | 159 | ||
165 | static const struct v4l2_queryctrl no_ctl = { | 160 | static const struct v4l2_queryctrl no_ctl = { |
166 | .name = "42", | 161 | .name = "42", |
167 | .flags = V4L2_CTRL_FLAG_DISABLED, | 162 | .flags = V4L2_CTRL_FLAG_DISABLED, |
168 | }; | 163 | }; |
169 | 164 | ||
170 | static struct cx88_ctrl cx8800_ctls[] = { | 165 | static struct cx88_ctrl cx8800_ctls[] = { |
171 | /* --- video --- */ | 166 | /* --- video --- */ |
172 | { | 167 | { |
173 | .v = { | 168 | .v = { |
174 | .id = V4L2_CID_BRIGHTNESS, | 169 | .id = V4L2_CID_BRIGHTNESS, |
175 | .name = "Brightness", | 170 | .name = "Brightness", |
176 | .minimum = 0x00, | 171 | .minimum = 0x00, |
177 | .maximum = 0xff, | 172 | .maximum = 0xff, |
178 | .step = 1, | 173 | .step = 1, |
179 | .default_value = 0x7f, | 174 | .default_value = 0x7f, |
180 | .type = V4L2_CTRL_TYPE_INTEGER, | 175 | .type = V4L2_CTRL_TYPE_INTEGER, |
181 | }, | 176 | }, |
182 | .off = 128, | 177 | .off = 128, |
183 | .reg = MO_CONTR_BRIGHT, | 178 | .reg = MO_CONTR_BRIGHT, |
184 | .mask = 0x00ff, | 179 | .mask = 0x00ff, |
185 | .shift = 0, | 180 | .shift = 0, |
186 | },{ | 181 | },{ |
187 | .v = { | 182 | .v = { |
188 | .id = V4L2_CID_CONTRAST, | 183 | .id = V4L2_CID_CONTRAST, |
189 | .name = "Contrast", | 184 | .name = "Contrast", |
190 | .minimum = 0, | 185 | .minimum = 0, |
191 | .maximum = 0xff, | 186 | .maximum = 0xff, |
192 | .step = 1, | 187 | .step = 1, |
193 | .default_value = 0x3f, | 188 | .default_value = 0x3f, |
194 | .type = V4L2_CTRL_TYPE_INTEGER, | 189 | .type = V4L2_CTRL_TYPE_INTEGER, |
195 | }, | 190 | }, |
196 | .off = 0, | 191 | .off = 0, |
197 | .reg = MO_CONTR_BRIGHT, | 192 | .reg = MO_CONTR_BRIGHT, |
198 | .mask = 0xff00, | 193 | .mask = 0xff00, |
199 | .shift = 8, | 194 | .shift = 8, |
200 | },{ | 195 | },{ |
201 | .v = { | 196 | .v = { |
202 | .id = V4L2_CID_HUE, | 197 | .id = V4L2_CID_HUE, |
203 | .name = "Hue", | 198 | .name = "Hue", |
204 | .minimum = 0, | 199 | .minimum = 0, |
205 | .maximum = 0xff, | 200 | .maximum = 0xff, |
206 | .step = 1, | 201 | .step = 1, |
207 | .default_value = 0x7f, | 202 | .default_value = 0x7f, |
208 | .type = V4L2_CTRL_TYPE_INTEGER, | 203 | .type = V4L2_CTRL_TYPE_INTEGER, |
209 | }, | 204 | }, |
210 | .off = 128, | 205 | .off = 128, |
211 | .reg = MO_HUE, | 206 | .reg = MO_HUE, |
212 | .mask = 0x00ff, | 207 | .mask = 0x00ff, |
213 | .shift = 0, | 208 | .shift = 0, |
214 | },{ | 209 | },{ |
215 | /* strictly, this only describes only U saturation. | 210 | /* strictly, this only describes only U saturation. |
216 | * V saturation is handled specially through code. | 211 | * V saturation is handled specially through code. |
217 | */ | 212 | */ |
218 | .v = { | 213 | .v = { |
219 | .id = V4L2_CID_SATURATION, | 214 | .id = V4L2_CID_SATURATION, |
220 | .name = "Saturation", | 215 | .name = "Saturation", |
221 | .minimum = 0, | 216 | .minimum = 0, |
222 | .maximum = 0xff, | 217 | .maximum = 0xff, |
223 | .step = 1, | 218 | .step = 1, |
224 | .default_value = 0x7f, | 219 | .default_value = 0x7f, |
225 | .type = V4L2_CTRL_TYPE_INTEGER, | 220 | .type = V4L2_CTRL_TYPE_INTEGER, |
226 | }, | 221 | }, |
227 | .off = 0, | 222 | .off = 0, |
228 | .reg = MO_UV_SATURATION, | 223 | .reg = MO_UV_SATURATION, |
229 | .mask = 0x00ff, | 224 | .mask = 0x00ff, |
230 | .shift = 0, | 225 | .shift = 0, |
231 | },{ | 226 | },{ |
232 | .v = { | 227 | .v = { |
233 | .id = V4L2_CID_CHROMA_AGC, | 228 | .id = V4L2_CID_CHROMA_AGC, |
234 | .name = "Chroma AGC", | 229 | .name = "Chroma AGC", |
235 | .minimum = 0, | 230 | .minimum = 0, |
236 | .maximum = 1, | 231 | .maximum = 1, |
237 | .default_value = 0x1, | 232 | .default_value = 0x1, |
238 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 233 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
239 | }, | 234 | }, |
240 | .reg = MO_INPUT_FORMAT, | 235 | .reg = MO_INPUT_FORMAT, |
241 | .mask = 1 << 10, | 236 | .mask = 1 << 10, |
242 | .shift = 10, | 237 | .shift = 10, |
243 | }, { | 238 | }, { |
244 | .v = { | 239 | .v = { |
245 | .id = V4L2_CID_COLOR_KILLER, | 240 | .id = V4L2_CID_COLOR_KILLER, |
246 | .name = "Color killer", | 241 | .name = "Color killer", |
247 | .minimum = 0, | 242 | .minimum = 0, |
248 | .maximum = 1, | 243 | .maximum = 1, |
249 | .default_value = 0x1, | 244 | .default_value = 0x1, |
250 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 245 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
251 | }, | 246 | }, |
252 | .reg = MO_INPUT_FORMAT, | 247 | .reg = MO_INPUT_FORMAT, |
253 | .mask = 1 << 9, | 248 | .mask = 1 << 9, |
254 | .shift = 9, | 249 | .shift = 9, |
255 | }, { | 250 | }, { |
256 | /* --- audio --- */ | 251 | /* --- audio --- */ |
257 | .v = { | 252 | .v = { |
258 | .id = V4L2_CID_AUDIO_MUTE, | 253 | .id = V4L2_CID_AUDIO_MUTE, |
259 | .name = "Mute", | 254 | .name = "Mute", |
260 | .minimum = 0, | 255 | .minimum = 0, |
261 | .maximum = 1, | 256 | .maximum = 1, |
262 | .default_value = 1, | 257 | .default_value = 1, |
263 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 258 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
264 | }, | 259 | }, |
265 | .reg = AUD_VOL_CTL, | 260 | .reg = AUD_VOL_CTL, |
266 | .sreg = SHADOW_AUD_VOL_CTL, | 261 | .sreg = SHADOW_AUD_VOL_CTL, |
267 | .mask = (1 << 6), | 262 | .mask = (1 << 6), |
268 | .shift = 6, | 263 | .shift = 6, |
269 | },{ | 264 | },{ |
270 | .v = { | 265 | .v = { |
271 | .id = V4L2_CID_AUDIO_VOLUME, | 266 | .id = V4L2_CID_AUDIO_VOLUME, |
272 | .name = "Volume", | 267 | .name = "Volume", |
273 | .minimum = 0, | 268 | .minimum = 0, |
274 | .maximum = 0x3f, | 269 | .maximum = 0x3f, |
275 | .step = 1, | 270 | .step = 1, |
276 | .default_value = 0x3f, | 271 | .default_value = 0x3f, |
277 | .type = V4L2_CTRL_TYPE_INTEGER, | 272 | .type = V4L2_CTRL_TYPE_INTEGER, |
278 | }, | 273 | }, |
279 | .reg = AUD_VOL_CTL, | 274 | .reg = AUD_VOL_CTL, |
280 | .sreg = SHADOW_AUD_VOL_CTL, | 275 | .sreg = SHADOW_AUD_VOL_CTL, |
281 | .mask = 0x3f, | 276 | .mask = 0x3f, |
282 | .shift = 0, | 277 | .shift = 0, |
283 | },{ | 278 | },{ |
284 | .v = { | 279 | .v = { |
285 | .id = V4L2_CID_AUDIO_BALANCE, | 280 | .id = V4L2_CID_AUDIO_BALANCE, |
286 | .name = "Balance", | 281 | .name = "Balance", |
287 | .minimum = 0, | 282 | .minimum = 0, |
288 | .maximum = 0x7f, | 283 | .maximum = 0x7f, |
289 | .step = 1, | 284 | .step = 1, |
290 | .default_value = 0x40, | 285 | .default_value = 0x40, |
291 | .type = V4L2_CTRL_TYPE_INTEGER, | 286 | .type = V4L2_CTRL_TYPE_INTEGER, |
292 | }, | 287 | }, |
293 | .reg = AUD_BAL_CTL, | 288 | .reg = AUD_BAL_CTL, |
294 | .sreg = SHADOW_AUD_BAL_CTL, | 289 | .sreg = SHADOW_AUD_BAL_CTL, |
295 | .mask = 0x7f, | 290 | .mask = 0x7f, |
296 | .shift = 0, | 291 | .shift = 0, |
297 | } | 292 | } |
298 | }; | 293 | }; |
299 | static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls); | 294 | static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls); |
300 | 295 | ||
301 | /* Must be sorted from low to high control ID! */ | 296 | /* Must be sorted from low to high control ID! */ |
302 | const u32 cx88_user_ctrls[] = { | 297 | const u32 cx88_user_ctrls[] = { |
303 | V4L2_CID_USER_CLASS, | 298 | V4L2_CID_USER_CLASS, |
304 | V4L2_CID_BRIGHTNESS, | 299 | V4L2_CID_BRIGHTNESS, |
305 | V4L2_CID_CONTRAST, | 300 | V4L2_CID_CONTRAST, |
306 | V4L2_CID_SATURATION, | 301 | V4L2_CID_SATURATION, |
307 | V4L2_CID_HUE, | 302 | V4L2_CID_HUE, |
308 | V4L2_CID_AUDIO_VOLUME, | 303 | V4L2_CID_AUDIO_VOLUME, |
309 | V4L2_CID_AUDIO_BALANCE, | 304 | V4L2_CID_AUDIO_BALANCE, |
310 | V4L2_CID_AUDIO_MUTE, | 305 | V4L2_CID_AUDIO_MUTE, |
311 | V4L2_CID_CHROMA_AGC, | 306 | V4L2_CID_CHROMA_AGC, |
312 | V4L2_CID_COLOR_KILLER, | 307 | V4L2_CID_COLOR_KILLER, |
313 | 0 | 308 | 0 |
314 | }; | 309 | }; |
315 | EXPORT_SYMBOL(cx88_user_ctrls); | 310 | EXPORT_SYMBOL(cx88_user_ctrls); |
316 | 311 | ||
317 | static const u32 *ctrl_classes[] = { | 312 | static const u32 *ctrl_classes[] = { |
318 | cx88_user_ctrls, | 313 | cx88_user_ctrls, |
319 | NULL | 314 | NULL |
320 | }; | 315 | }; |
321 | 316 | ||
322 | int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) | 317 | int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) |
323 | { | 318 | { |
324 | int i; | 319 | int i; |
325 | 320 | ||
326 | if (qctrl->id < V4L2_CID_BASE || | 321 | if (qctrl->id < V4L2_CID_BASE || |
327 | qctrl->id >= V4L2_CID_LASTP1) | 322 | qctrl->id >= V4L2_CID_LASTP1) |
328 | return -EINVAL; | 323 | return -EINVAL; |
329 | for (i = 0; i < CX8800_CTLS; i++) | 324 | for (i = 0; i < CX8800_CTLS; i++) |
330 | if (cx8800_ctls[i].v.id == qctrl->id) | 325 | if (cx8800_ctls[i].v.id == qctrl->id) |
331 | break; | 326 | break; |
332 | if (i == CX8800_CTLS) { | 327 | if (i == CX8800_CTLS) { |
333 | *qctrl = no_ctl; | 328 | *qctrl = no_ctl; |
334 | return 0; | 329 | return 0; |
335 | } | 330 | } |
336 | *qctrl = cx8800_ctls[i].v; | 331 | *qctrl = cx8800_ctls[i].v; |
337 | /* Report chroma AGC as inactive when SECAM is selected */ | 332 | /* Report chroma AGC as inactive when SECAM is selected */ |
338 | if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && | 333 | if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && |
339 | core->tvnorm & V4L2_STD_SECAM) | 334 | core->tvnorm & V4L2_STD_SECAM) |
340 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 335 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
341 | 336 | ||
342 | return 0; | 337 | return 0; |
343 | } | 338 | } |
344 | EXPORT_SYMBOL(cx8800_ctrl_query); | 339 | EXPORT_SYMBOL(cx8800_ctrl_query); |
345 | 340 | ||
346 | /* ------------------------------------------------------------------- */ | 341 | /* ------------------------------------------------------------------- */ |
347 | /* resource management */ | 342 | /* resource management */ |
348 | 343 | ||
349 | static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) | 344 | static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) |
350 | { | 345 | { |
351 | struct cx88_core *core = dev->core; | 346 | struct cx88_core *core = dev->core; |
352 | if (fh->resources & bit) | 347 | if (fh->resources & bit) |
353 | /* have it already allocated */ | 348 | /* have it already allocated */ |
354 | return 1; | 349 | return 1; |
355 | 350 | ||
356 | /* is it free? */ | 351 | /* is it free? */ |
357 | mutex_lock(&core->lock); | 352 | mutex_lock(&core->lock); |
358 | if (dev->resources & bit) { | 353 | if (dev->resources & bit) { |
359 | /* no, someone else uses it */ | 354 | /* no, someone else uses it */ |
360 | mutex_unlock(&core->lock); | 355 | mutex_unlock(&core->lock); |
361 | return 0; | 356 | return 0; |
362 | } | 357 | } |
363 | /* it's free, grab it */ | 358 | /* it's free, grab it */ |
364 | fh->resources |= bit; | 359 | fh->resources |= bit; |
365 | dev->resources |= bit; | 360 | dev->resources |= bit; |
366 | dprintk(1,"res: get %d\n",bit); | 361 | dprintk(1,"res: get %d\n",bit); |
367 | mutex_unlock(&core->lock); | 362 | mutex_unlock(&core->lock); |
368 | return 1; | 363 | return 1; |
369 | } | 364 | } |
370 | 365 | ||
371 | static | 366 | static |
372 | int res_check(struct cx8800_fh *fh, unsigned int bit) | 367 | int res_check(struct cx8800_fh *fh, unsigned int bit) |
373 | { | 368 | { |
374 | return (fh->resources & bit); | 369 | return (fh->resources & bit); |
375 | } | 370 | } |
376 | 371 | ||
377 | static | 372 | static |
378 | int res_locked(struct cx8800_dev *dev, unsigned int bit) | 373 | int res_locked(struct cx8800_dev *dev, unsigned int bit) |
379 | { | 374 | { |
380 | return (dev->resources & bit); | 375 | return (dev->resources & bit); |
381 | } | 376 | } |
382 | 377 | ||
383 | static | 378 | static |
384 | void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) | 379 | void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) |
385 | { | 380 | { |
386 | struct cx88_core *core = dev->core; | 381 | struct cx88_core *core = dev->core; |
387 | BUG_ON((fh->resources & bits) != bits); | 382 | BUG_ON((fh->resources & bits) != bits); |
388 | 383 | ||
389 | mutex_lock(&core->lock); | 384 | mutex_lock(&core->lock); |
390 | fh->resources &= ~bits; | 385 | fh->resources &= ~bits; |
391 | dev->resources &= ~bits; | 386 | dev->resources &= ~bits; |
392 | dprintk(1,"res: put %d\n",bits); | 387 | dprintk(1,"res: put %d\n",bits); |
393 | mutex_unlock(&core->lock); | 388 | mutex_unlock(&core->lock); |
394 | } | 389 | } |
395 | 390 | ||
396 | /* ------------------------------------------------------------------ */ | 391 | /* ------------------------------------------------------------------ */ |
397 | 392 | ||
398 | int cx88_video_mux(struct cx88_core *core, unsigned int input) | 393 | int cx88_video_mux(struct cx88_core *core, unsigned int input) |
399 | { | 394 | { |
400 | /* struct cx88_core *core = dev->core; */ | 395 | /* struct cx88_core *core = dev->core; */ |
401 | 396 | ||
402 | dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", | 397 | dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", |
403 | input, INPUT(input).vmux, | 398 | input, INPUT(input).vmux, |
404 | INPUT(input).gpio0,INPUT(input).gpio1, | 399 | INPUT(input).gpio0,INPUT(input).gpio1, |
405 | INPUT(input).gpio2,INPUT(input).gpio3); | 400 | INPUT(input).gpio2,INPUT(input).gpio3); |
406 | core->input = input; | 401 | core->input = input; |
407 | cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); | 402 | cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); |
408 | cx_write(MO_GP3_IO, INPUT(input).gpio3); | 403 | cx_write(MO_GP3_IO, INPUT(input).gpio3); |
409 | cx_write(MO_GP0_IO, INPUT(input).gpio0); | 404 | cx_write(MO_GP0_IO, INPUT(input).gpio0); |
410 | cx_write(MO_GP1_IO, INPUT(input).gpio1); | 405 | cx_write(MO_GP1_IO, INPUT(input).gpio1); |
411 | cx_write(MO_GP2_IO, INPUT(input).gpio2); | 406 | cx_write(MO_GP2_IO, INPUT(input).gpio2); |
412 | 407 | ||
413 | switch (INPUT(input).type) { | 408 | switch (INPUT(input).type) { |
414 | case CX88_VMUX_SVIDEO: | 409 | case CX88_VMUX_SVIDEO: |
415 | cx_set(MO_AFECFG_IO, 0x00000001); | 410 | cx_set(MO_AFECFG_IO, 0x00000001); |
416 | cx_set(MO_INPUT_FORMAT, 0x00010010); | 411 | cx_set(MO_INPUT_FORMAT, 0x00010010); |
417 | cx_set(MO_FILTER_EVEN, 0x00002020); | 412 | cx_set(MO_FILTER_EVEN, 0x00002020); |
418 | cx_set(MO_FILTER_ODD, 0x00002020); | 413 | cx_set(MO_FILTER_ODD, 0x00002020); |
419 | break; | 414 | break; |
420 | default: | 415 | default: |
421 | cx_clear(MO_AFECFG_IO, 0x00000001); | 416 | cx_clear(MO_AFECFG_IO, 0x00000001); |
422 | cx_clear(MO_INPUT_FORMAT, 0x00010010); | 417 | cx_clear(MO_INPUT_FORMAT, 0x00010010); |
423 | cx_clear(MO_FILTER_EVEN, 0x00002020); | 418 | cx_clear(MO_FILTER_EVEN, 0x00002020); |
424 | cx_clear(MO_FILTER_ODD, 0x00002020); | 419 | cx_clear(MO_FILTER_ODD, 0x00002020); |
425 | break; | 420 | break; |
426 | } | 421 | } |
427 | 422 | ||
428 | /* if there are audioroutes defined, we have an external | 423 | /* if there are audioroutes defined, we have an external |
429 | ADC to deal with audio */ | 424 | ADC to deal with audio */ |
430 | if (INPUT(input).audioroute) { | 425 | if (INPUT(input).audioroute) { |
431 | /* The wm8775 module has the "2" route hardwired into | 426 | /* The wm8775 module has the "2" route hardwired into |
432 | the initialization. Some boards may use different | 427 | the initialization. Some boards may use different |
433 | routes for different inputs. HVR-1300 surely does */ | 428 | routes for different inputs. HVR-1300 surely does */ |
434 | if (core->board.audio_chip && | 429 | if (core->board.audio_chip && |
435 | core->board.audio_chip == V4L2_IDENT_WM8775) { | 430 | core->board.audio_chip == V4L2_IDENT_WM8775) { |
436 | struct v4l2_routing route; | 431 | struct v4l2_routing route; |
437 | 432 | ||
438 | route.input = INPUT(input).audioroute; | 433 | route.input = INPUT(input).audioroute; |
439 | cx88_call_i2c_clients(core, | 434 | cx88_call_i2c_clients(core, |
440 | VIDIOC_INT_S_AUDIO_ROUTING, &route); | 435 | VIDIOC_INT_S_AUDIO_ROUTING, &route); |
441 | } | 436 | } |
442 | /* cx2388's C-ADC is connected to the tuner only. | 437 | /* cx2388's C-ADC is connected to the tuner only. |
443 | When used with S-Video, that ADC is busy dealing with | 438 | When used with S-Video, that ADC is busy dealing with |
444 | chroma, so an external must be used for baseband audio */ | 439 | chroma, so an external must be used for baseband audio */ |
445 | if (INPUT(input).type != CX88_VMUX_TELEVISION ) { | 440 | if (INPUT(input).type != CX88_VMUX_TELEVISION ) { |
446 | /* "I2S ADC mode" */ | 441 | /* "I2S ADC mode" */ |
447 | core->tvaudio = WW_I2SADC; | 442 | core->tvaudio = WW_I2SADC; |
448 | cx88_set_tvaudio(core); | 443 | cx88_set_tvaudio(core); |
449 | } else { | 444 | } else { |
450 | /* Normal mode */ | 445 | /* Normal mode */ |
451 | cx_write(AUD_I2SCNTL, 0x0); | 446 | cx_write(AUD_I2SCNTL, 0x0); |
452 | cx_clear(AUD_CTL, EN_I2SIN_ENABLE); | 447 | cx_clear(AUD_CTL, EN_I2SIN_ENABLE); |
453 | } | 448 | } |
454 | } | 449 | } |
455 | 450 | ||
456 | return 0; | 451 | return 0; |
457 | } | 452 | } |
458 | EXPORT_SYMBOL(cx88_video_mux); | 453 | EXPORT_SYMBOL(cx88_video_mux); |
459 | 454 | ||
460 | /* ------------------------------------------------------------------ */ | 455 | /* ------------------------------------------------------------------ */ |
461 | 456 | ||
462 | static int start_video_dma(struct cx8800_dev *dev, | 457 | static int start_video_dma(struct cx8800_dev *dev, |
463 | struct cx88_dmaqueue *q, | 458 | struct cx88_dmaqueue *q, |
464 | struct cx88_buffer *buf) | 459 | struct cx88_buffer *buf) |
465 | { | 460 | { |
466 | struct cx88_core *core = dev->core; | 461 | struct cx88_core *core = dev->core; |
467 | 462 | ||
468 | /* setup fifo + format */ | 463 | /* setup fifo + format */ |
469 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], | 464 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], |
470 | buf->bpl, buf->risc.dma); | 465 | buf->bpl, buf->risc.dma); |
471 | cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); | 466 | cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); |
472 | cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); | 467 | cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); |
473 | 468 | ||
474 | /* reset counter */ | 469 | /* reset counter */ |
475 | cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); | 470 | cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); |
476 | q->count = 1; | 471 | q->count = 1; |
477 | 472 | ||
478 | /* enable irqs */ | 473 | /* enable irqs */ |
479 | cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); | 474 | cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); |
480 | 475 | ||
481 | /* Enables corresponding bits at PCI_INT_STAT: | 476 | /* Enables corresponding bits at PCI_INT_STAT: |
482 | bits 0 to 4: video, audio, transport stream, VIP, Host | 477 | bits 0 to 4: video, audio, transport stream, VIP, Host |
483 | bit 7: timer | 478 | bit 7: timer |
484 | bits 8 and 9: DMA complete for: SRC, DST | 479 | bits 8 and 9: DMA complete for: SRC, DST |
485 | bits 10 and 11: BERR signal asserted for RISC: RD, WR | 480 | bits 10 and 11: BERR signal asserted for RISC: RD, WR |
486 | bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB | 481 | bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB |
487 | */ | 482 | */ |
488 | cx_set(MO_VID_INTMSK, 0x0f0011); | 483 | cx_set(MO_VID_INTMSK, 0x0f0011); |
489 | 484 | ||
490 | /* enable capture */ | 485 | /* enable capture */ |
491 | cx_set(VID_CAPTURE_CONTROL,0x06); | 486 | cx_set(VID_CAPTURE_CONTROL,0x06); |
492 | 487 | ||
493 | /* start dma */ | 488 | /* start dma */ |
494 | cx_set(MO_DEV_CNTRL2, (1<<5)); | 489 | cx_set(MO_DEV_CNTRL2, (1<<5)); |
495 | cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ | 490 | cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ |
496 | 491 | ||
497 | return 0; | 492 | return 0; |
498 | } | 493 | } |
499 | 494 | ||
500 | #ifdef CONFIG_PM | 495 | #ifdef CONFIG_PM |
501 | static int stop_video_dma(struct cx8800_dev *dev) | 496 | static int stop_video_dma(struct cx8800_dev *dev) |
502 | { | 497 | { |
503 | struct cx88_core *core = dev->core; | 498 | struct cx88_core *core = dev->core; |
504 | 499 | ||
505 | /* stop dma */ | 500 | /* stop dma */ |
506 | cx_clear(MO_VID_DMACNTRL, 0x11); | 501 | cx_clear(MO_VID_DMACNTRL, 0x11); |
507 | 502 | ||
508 | /* disable capture */ | 503 | /* disable capture */ |
509 | cx_clear(VID_CAPTURE_CONTROL,0x06); | 504 | cx_clear(VID_CAPTURE_CONTROL,0x06); |
510 | 505 | ||
511 | /* disable irqs */ | 506 | /* disable irqs */ |
512 | cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); | 507 | cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); |
513 | cx_clear(MO_VID_INTMSK, 0x0f0011); | 508 | cx_clear(MO_VID_INTMSK, 0x0f0011); |
514 | return 0; | 509 | return 0; |
515 | } | 510 | } |
516 | #endif | 511 | #endif |
517 | 512 | ||
518 | static int restart_video_queue(struct cx8800_dev *dev, | 513 | static int restart_video_queue(struct cx8800_dev *dev, |
519 | struct cx88_dmaqueue *q) | 514 | struct cx88_dmaqueue *q) |
520 | { | 515 | { |
521 | struct cx88_core *core = dev->core; | 516 | struct cx88_core *core = dev->core; |
522 | struct cx88_buffer *buf, *prev; | 517 | struct cx88_buffer *buf, *prev; |
523 | 518 | ||
524 | if (!list_empty(&q->active)) { | 519 | if (!list_empty(&q->active)) { |
525 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); | 520 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); |
526 | dprintk(2,"restart_queue [%p/%d]: restart dma\n", | 521 | dprintk(2,"restart_queue [%p/%d]: restart dma\n", |
527 | buf, buf->vb.i); | 522 | buf, buf->vb.i); |
528 | start_video_dma(dev, q, buf); | 523 | start_video_dma(dev, q, buf); |
529 | list_for_each_entry(buf, &q->active, vb.queue) | 524 | list_for_each_entry(buf, &q->active, vb.queue) |
530 | buf->count = q->count++; | 525 | buf->count = q->count++; |
531 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 526 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
532 | return 0; | 527 | return 0; |
533 | } | 528 | } |
534 | 529 | ||
535 | prev = NULL; | 530 | prev = NULL; |
536 | for (;;) { | 531 | for (;;) { |
537 | if (list_empty(&q->queued)) | 532 | if (list_empty(&q->queued)) |
538 | return 0; | 533 | return 0; |
539 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); | 534 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); |
540 | if (NULL == prev) { | 535 | if (NULL == prev) { |
541 | list_move_tail(&buf->vb.queue, &q->active); | 536 | list_move_tail(&buf->vb.queue, &q->active); |
542 | start_video_dma(dev, q, buf); | 537 | start_video_dma(dev, q, buf); |
543 | buf->vb.state = VIDEOBUF_ACTIVE; | 538 | buf->vb.state = VIDEOBUF_ACTIVE; |
544 | buf->count = q->count++; | 539 | buf->count = q->count++; |
545 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 540 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
546 | dprintk(2,"[%p/%d] restart_queue - first active\n", | 541 | dprintk(2,"[%p/%d] restart_queue - first active\n", |
547 | buf,buf->vb.i); | 542 | buf,buf->vb.i); |
548 | 543 | ||
549 | } else if (prev->vb.width == buf->vb.width && | 544 | } else if (prev->vb.width == buf->vb.width && |
550 | prev->vb.height == buf->vb.height && | 545 | prev->vb.height == buf->vb.height && |
551 | prev->fmt == buf->fmt) { | 546 | prev->fmt == buf->fmt) { |
552 | list_move_tail(&buf->vb.queue, &q->active); | 547 | list_move_tail(&buf->vb.queue, &q->active); |
553 | buf->vb.state = VIDEOBUF_ACTIVE; | 548 | buf->vb.state = VIDEOBUF_ACTIVE; |
554 | buf->count = q->count++; | 549 | buf->count = q->count++; |
555 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 550 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
556 | dprintk(2,"[%p/%d] restart_queue - move to active\n", | 551 | dprintk(2,"[%p/%d] restart_queue - move to active\n", |
557 | buf,buf->vb.i); | 552 | buf,buf->vb.i); |
558 | } else { | 553 | } else { |
559 | return 0; | 554 | return 0; |
560 | } | 555 | } |
561 | prev = buf; | 556 | prev = buf; |
562 | } | 557 | } |
563 | } | 558 | } |
564 | 559 | ||
565 | /* ------------------------------------------------------------------ */ | 560 | /* ------------------------------------------------------------------ */ |
566 | 561 | ||
567 | static int | 562 | static int |
568 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | 563 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) |
569 | { | 564 | { |
570 | struct cx8800_fh *fh = q->priv_data; | 565 | struct cx8800_fh *fh = q->priv_data; |
571 | 566 | ||
572 | *size = fh->fmt->depth*fh->width*fh->height >> 3; | 567 | *size = fh->fmt->depth*fh->width*fh->height >> 3; |
573 | if (0 == *count) | 568 | if (0 == *count) |
574 | *count = 32; | 569 | *count = 32; |
575 | while (*size * *count > vid_limit * 1024 * 1024) | 570 | while (*size * *count > vid_limit * 1024 * 1024) |
576 | (*count)--; | 571 | (*count)--; |
577 | return 0; | 572 | return 0; |
578 | } | 573 | } |
579 | 574 | ||
580 | static int | 575 | static int |
581 | buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | 576 | buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, |
582 | enum v4l2_field field) | 577 | enum v4l2_field field) |
583 | { | 578 | { |
584 | struct cx8800_fh *fh = q->priv_data; | 579 | struct cx8800_fh *fh = q->priv_data; |
585 | struct cx8800_dev *dev = fh->dev; | 580 | struct cx8800_dev *dev = fh->dev; |
586 | struct cx88_core *core = dev->core; | 581 | struct cx88_core *core = dev->core; |
587 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | 582 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); |
588 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | 583 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); |
589 | int rc, init_buffer = 0; | 584 | int rc, init_buffer = 0; |
590 | 585 | ||
591 | BUG_ON(NULL == fh->fmt); | 586 | BUG_ON(NULL == fh->fmt); |
592 | if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || | 587 | if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || |
593 | fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) | 588 | fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) |
594 | return -EINVAL; | 589 | return -EINVAL; |
595 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | 590 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; |
596 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | 591 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) |
597 | return -EINVAL; | 592 | return -EINVAL; |
598 | 593 | ||
599 | if (buf->fmt != fh->fmt || | 594 | if (buf->fmt != fh->fmt || |
600 | buf->vb.width != fh->width || | 595 | buf->vb.width != fh->width || |
601 | buf->vb.height != fh->height || | 596 | buf->vb.height != fh->height || |
602 | buf->vb.field != field) { | 597 | buf->vb.field != field) { |
603 | buf->fmt = fh->fmt; | 598 | buf->fmt = fh->fmt; |
604 | buf->vb.width = fh->width; | 599 | buf->vb.width = fh->width; |
605 | buf->vb.height = fh->height; | 600 | buf->vb.height = fh->height; |
606 | buf->vb.field = field; | 601 | buf->vb.field = field; |
607 | init_buffer = 1; | 602 | init_buffer = 1; |
608 | } | 603 | } |
609 | 604 | ||
610 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 605 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
611 | init_buffer = 1; | 606 | init_buffer = 1; |
612 | if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) | 607 | if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) |
613 | goto fail; | 608 | goto fail; |
614 | } | 609 | } |
615 | 610 | ||
616 | if (init_buffer) { | 611 | if (init_buffer) { |
617 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; | 612 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; |
618 | switch (buf->vb.field) { | 613 | switch (buf->vb.field) { |
619 | case V4L2_FIELD_TOP: | 614 | case V4L2_FIELD_TOP: |
620 | cx88_risc_buffer(dev->pci, &buf->risc, | 615 | cx88_risc_buffer(dev->pci, &buf->risc, |
621 | dma->sglist, 0, UNSET, | 616 | dma->sglist, 0, UNSET, |
622 | buf->bpl, 0, buf->vb.height); | 617 | buf->bpl, 0, buf->vb.height); |
623 | break; | 618 | break; |
624 | case V4L2_FIELD_BOTTOM: | 619 | case V4L2_FIELD_BOTTOM: |
625 | cx88_risc_buffer(dev->pci, &buf->risc, | 620 | cx88_risc_buffer(dev->pci, &buf->risc, |
626 | dma->sglist, UNSET, 0, | 621 | dma->sglist, UNSET, 0, |
627 | buf->bpl, 0, buf->vb.height); | 622 | buf->bpl, 0, buf->vb.height); |
628 | break; | 623 | break; |
629 | case V4L2_FIELD_INTERLACED: | 624 | case V4L2_FIELD_INTERLACED: |
630 | cx88_risc_buffer(dev->pci, &buf->risc, | 625 | cx88_risc_buffer(dev->pci, &buf->risc, |
631 | dma->sglist, 0, buf->bpl, | 626 | dma->sglist, 0, buf->bpl, |
632 | buf->bpl, buf->bpl, | 627 | buf->bpl, buf->bpl, |
633 | buf->vb.height >> 1); | 628 | buf->vb.height >> 1); |
634 | break; | 629 | break; |
635 | case V4L2_FIELD_SEQ_TB: | 630 | case V4L2_FIELD_SEQ_TB: |
636 | cx88_risc_buffer(dev->pci, &buf->risc, | 631 | cx88_risc_buffer(dev->pci, &buf->risc, |
637 | dma->sglist, | 632 | dma->sglist, |
638 | 0, buf->bpl * (buf->vb.height >> 1), | 633 | 0, buf->bpl * (buf->vb.height >> 1), |
639 | buf->bpl, 0, | 634 | buf->bpl, 0, |
640 | buf->vb.height >> 1); | 635 | buf->vb.height >> 1); |
641 | break; | 636 | break; |
642 | case V4L2_FIELD_SEQ_BT: | 637 | case V4L2_FIELD_SEQ_BT: |
643 | cx88_risc_buffer(dev->pci, &buf->risc, | 638 | cx88_risc_buffer(dev->pci, &buf->risc, |
644 | dma->sglist, | 639 | dma->sglist, |
645 | buf->bpl * (buf->vb.height >> 1), 0, | 640 | buf->bpl * (buf->vb.height >> 1), 0, |
646 | buf->bpl, 0, | 641 | buf->bpl, 0, |
647 | buf->vb.height >> 1); | 642 | buf->vb.height >> 1); |
648 | break; | 643 | break; |
649 | default: | 644 | default: |
650 | BUG(); | 645 | BUG(); |
651 | } | 646 | } |
652 | } | 647 | } |
653 | dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | 648 | dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", |
654 | buf, buf->vb.i, | 649 | buf, buf->vb.i, |
655 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, | 650 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, |
656 | (unsigned long)buf->risc.dma); | 651 | (unsigned long)buf->risc.dma); |
657 | 652 | ||
658 | buf->vb.state = VIDEOBUF_PREPARED; | 653 | buf->vb.state = VIDEOBUF_PREPARED; |
659 | return 0; | 654 | return 0; |
660 | 655 | ||
661 | fail: | 656 | fail: |
662 | cx88_free_buffer(q,buf); | 657 | cx88_free_buffer(q,buf); |
663 | return rc; | 658 | return rc; |
664 | } | 659 | } |
665 | 660 | ||
666 | static void | 661 | static void |
667 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | 662 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) |
668 | { | 663 | { |
669 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | 664 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); |
670 | struct cx88_buffer *prev; | 665 | struct cx88_buffer *prev; |
671 | struct cx8800_fh *fh = vq->priv_data; | 666 | struct cx8800_fh *fh = vq->priv_data; |
672 | struct cx8800_dev *dev = fh->dev; | 667 | struct cx8800_dev *dev = fh->dev; |
673 | struct cx88_core *core = dev->core; | 668 | struct cx88_core *core = dev->core; |
674 | struct cx88_dmaqueue *q = &dev->vidq; | 669 | struct cx88_dmaqueue *q = &dev->vidq; |
675 | 670 | ||
676 | /* add jump to stopper */ | 671 | /* add jump to stopper */ |
677 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | 672 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); |
678 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | 673 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); |
679 | 674 | ||
680 | if (!list_empty(&q->queued)) { | 675 | if (!list_empty(&q->queued)) { |
681 | list_add_tail(&buf->vb.queue,&q->queued); | 676 | list_add_tail(&buf->vb.queue,&q->queued); |
682 | buf->vb.state = VIDEOBUF_QUEUED; | 677 | buf->vb.state = VIDEOBUF_QUEUED; |
683 | dprintk(2,"[%p/%d] buffer_queue - append to queued\n", | 678 | dprintk(2,"[%p/%d] buffer_queue - append to queued\n", |
684 | buf, buf->vb.i); | 679 | buf, buf->vb.i); |
685 | 680 | ||
686 | } else if (list_empty(&q->active)) { | 681 | } else if (list_empty(&q->active)) { |
687 | list_add_tail(&buf->vb.queue,&q->active); | 682 | list_add_tail(&buf->vb.queue,&q->active); |
688 | start_video_dma(dev, q, buf); | 683 | start_video_dma(dev, q, buf); |
689 | buf->vb.state = VIDEOBUF_ACTIVE; | 684 | buf->vb.state = VIDEOBUF_ACTIVE; |
690 | buf->count = q->count++; | 685 | buf->count = q->count++; |
691 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | 686 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); |
692 | dprintk(2,"[%p/%d] buffer_queue - first active\n", | 687 | dprintk(2,"[%p/%d] buffer_queue - first active\n", |
693 | buf, buf->vb.i); | 688 | buf, buf->vb.i); |
694 | 689 | ||
695 | } else { | 690 | } else { |
696 | prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); | 691 | prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); |
697 | if (prev->vb.width == buf->vb.width && | 692 | if (prev->vb.width == buf->vb.width && |
698 | prev->vb.height == buf->vb.height && | 693 | prev->vb.height == buf->vb.height && |
699 | prev->fmt == buf->fmt) { | 694 | prev->fmt == buf->fmt) { |
700 | list_add_tail(&buf->vb.queue,&q->active); | 695 | list_add_tail(&buf->vb.queue,&q->active); |
701 | buf->vb.state = VIDEOBUF_ACTIVE; | 696 | buf->vb.state = VIDEOBUF_ACTIVE; |
702 | buf->count = q->count++; | 697 | buf->count = q->count++; |
703 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 698 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
704 | dprintk(2,"[%p/%d] buffer_queue - append to active\n", | 699 | dprintk(2,"[%p/%d] buffer_queue - append to active\n", |
705 | buf, buf->vb.i); | 700 | buf, buf->vb.i); |
706 | 701 | ||
707 | } else { | 702 | } else { |
708 | list_add_tail(&buf->vb.queue,&q->queued); | 703 | list_add_tail(&buf->vb.queue,&q->queued); |
709 | buf->vb.state = VIDEOBUF_QUEUED; | 704 | buf->vb.state = VIDEOBUF_QUEUED; |
710 | dprintk(2,"[%p/%d] buffer_queue - first queued\n", | 705 | dprintk(2,"[%p/%d] buffer_queue - first queued\n", |
711 | buf, buf->vb.i); | 706 | buf, buf->vb.i); |
712 | } | 707 | } |
713 | } | 708 | } |
714 | } | 709 | } |
715 | 710 | ||
716 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | 711 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) |
717 | { | 712 | { |
718 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | 713 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); |
719 | 714 | ||
720 | cx88_free_buffer(q,buf); | 715 | cx88_free_buffer(q,buf); |
721 | } | 716 | } |
722 | 717 | ||
723 | static struct videobuf_queue_ops cx8800_video_qops = { | 718 | static struct videobuf_queue_ops cx8800_video_qops = { |
724 | .buf_setup = buffer_setup, | 719 | .buf_setup = buffer_setup, |
725 | .buf_prepare = buffer_prepare, | 720 | .buf_prepare = buffer_prepare, |
726 | .buf_queue = buffer_queue, | 721 | .buf_queue = buffer_queue, |
727 | .buf_release = buffer_release, | 722 | .buf_release = buffer_release, |
728 | }; | 723 | }; |
729 | 724 | ||
730 | /* ------------------------------------------------------------------ */ | 725 | /* ------------------------------------------------------------------ */ |
731 | 726 | ||
732 | 727 | ||
733 | /* ------------------------------------------------------------------ */ | 728 | /* ------------------------------------------------------------------ */ |
734 | 729 | ||
735 | static struct videobuf_queue* get_queue(struct cx8800_fh *fh) | 730 | static struct videobuf_queue* get_queue(struct cx8800_fh *fh) |
736 | { | 731 | { |
737 | switch (fh->type) { | 732 | switch (fh->type) { |
738 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 733 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
739 | return &fh->vidq; | 734 | return &fh->vidq; |
740 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 735 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
741 | return &fh->vbiq; | 736 | return &fh->vbiq; |
742 | default: | 737 | default: |
743 | BUG(); | 738 | BUG(); |
744 | return NULL; | 739 | return NULL; |
745 | } | 740 | } |
746 | } | 741 | } |
747 | 742 | ||
748 | static int get_ressource(struct cx8800_fh *fh) | 743 | static int get_ressource(struct cx8800_fh *fh) |
749 | { | 744 | { |
750 | switch (fh->type) { | 745 | switch (fh->type) { |
751 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 746 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
752 | return RESOURCE_VIDEO; | 747 | return RESOURCE_VIDEO; |
753 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 748 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
754 | return RESOURCE_VBI; | 749 | return RESOURCE_VBI; |
755 | default: | 750 | default: |
756 | BUG(); | 751 | BUG(); |
757 | return 0; | 752 | return 0; |
758 | } | 753 | } |
759 | } | 754 | } |
760 | 755 | ||
761 | static int video_open(struct file *file) | 756 | static int video_open(struct file *file) |
762 | { | 757 | { |
763 | int minor = video_devdata(file)->minor; | 758 | int minor = video_devdata(file)->minor; |
764 | struct cx8800_dev *h,*dev = NULL; | 759 | struct cx8800_dev *h,*dev = NULL; |
765 | struct cx88_core *core; | 760 | struct cx88_core *core; |
766 | struct cx8800_fh *fh; | 761 | struct cx8800_fh *fh; |
767 | enum v4l2_buf_type type = 0; | 762 | enum v4l2_buf_type type = 0; |
768 | int radio = 0; | 763 | int radio = 0; |
769 | 764 | ||
770 | lock_kernel(); | 765 | lock_kernel(); |
771 | list_for_each_entry(h, &cx8800_devlist, devlist) { | 766 | list_for_each_entry(h, &cx8800_devlist, devlist) { |
772 | if (h->video_dev->minor == minor) { | 767 | if (h->video_dev->minor == minor) { |
773 | dev = h; | 768 | dev = h; |
774 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 769 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
775 | } | 770 | } |
776 | if (h->vbi_dev->minor == minor) { | 771 | if (h->vbi_dev->minor == minor) { |
777 | dev = h; | 772 | dev = h; |
778 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 773 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
779 | } | 774 | } |
780 | if (h->radio_dev && | 775 | if (h->radio_dev && |
781 | h->radio_dev->minor == minor) { | 776 | h->radio_dev->minor == minor) { |
782 | radio = 1; | 777 | radio = 1; |
783 | dev = h; | 778 | dev = h; |
784 | } | 779 | } |
785 | } | 780 | } |
786 | if (NULL == dev) { | 781 | if (NULL == dev) { |
787 | unlock_kernel(); | 782 | unlock_kernel(); |
788 | return -ENODEV; | 783 | return -ENODEV; |
789 | } | 784 | } |
790 | 785 | ||
791 | core = dev->core; | 786 | core = dev->core; |
792 | 787 | ||
793 | dprintk(1,"open minor=%d radio=%d type=%s\n", | 788 | dprintk(1,"open minor=%d radio=%d type=%s\n", |
794 | minor,radio,v4l2_type_names[type]); | 789 | minor,radio,v4l2_type_names[type]); |
795 | 790 | ||
796 | /* allocate + initialize per filehandle data */ | 791 | /* allocate + initialize per filehandle data */ |
797 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 792 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
798 | if (NULL == fh) { | 793 | if (NULL == fh) { |
799 | unlock_kernel(); | 794 | unlock_kernel(); |
800 | return -ENOMEM; | 795 | return -ENOMEM; |
801 | } | 796 | } |
802 | file->private_data = fh; | 797 | file->private_data = fh; |
803 | fh->dev = dev; | 798 | fh->dev = dev; |
804 | fh->radio = radio; | 799 | fh->radio = radio; |
805 | fh->type = type; | 800 | fh->type = type; |
806 | fh->width = 320; | 801 | fh->width = 320; |
807 | fh->height = 240; | 802 | fh->height = 240; |
808 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | 803 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
809 | 804 | ||
810 | videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops, | 805 | videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops, |
811 | &dev->pci->dev, &dev->slock, | 806 | &dev->pci->dev, &dev->slock, |
812 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 807 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
813 | V4L2_FIELD_INTERLACED, | 808 | V4L2_FIELD_INTERLACED, |
814 | sizeof(struct cx88_buffer), | 809 | sizeof(struct cx88_buffer), |
815 | fh); | 810 | fh); |
816 | videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, | 811 | videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, |
817 | &dev->pci->dev, &dev->slock, | 812 | &dev->pci->dev, &dev->slock, |
818 | V4L2_BUF_TYPE_VBI_CAPTURE, | 813 | V4L2_BUF_TYPE_VBI_CAPTURE, |
819 | V4L2_FIELD_SEQ_TB, | 814 | V4L2_FIELD_SEQ_TB, |
820 | sizeof(struct cx88_buffer), | 815 | sizeof(struct cx88_buffer), |
821 | fh); | 816 | fh); |
822 | 817 | ||
823 | if (fh->radio) { | 818 | if (fh->radio) { |
824 | dprintk(1,"video_open: setting radio device\n"); | 819 | dprintk(1,"video_open: setting radio device\n"); |
825 | cx_write(MO_GP3_IO, core->board.radio.gpio3); | 820 | cx_write(MO_GP3_IO, core->board.radio.gpio3); |
826 | cx_write(MO_GP0_IO, core->board.radio.gpio0); | 821 | cx_write(MO_GP0_IO, core->board.radio.gpio0); |
827 | cx_write(MO_GP1_IO, core->board.radio.gpio1); | 822 | cx_write(MO_GP1_IO, core->board.radio.gpio1); |
828 | cx_write(MO_GP2_IO, core->board.radio.gpio2); | 823 | cx_write(MO_GP2_IO, core->board.radio.gpio2); |
829 | if (core->board.radio.audioroute) { | 824 | if (core->board.radio.audioroute) { |
830 | if(core->board.audio_chip && | 825 | if(core->board.audio_chip && |
831 | core->board.audio_chip == V4L2_IDENT_WM8775) { | 826 | core->board.audio_chip == V4L2_IDENT_WM8775) { |
832 | struct v4l2_routing route; | 827 | struct v4l2_routing route; |
833 | 828 | ||
834 | route.input = core->board.radio.audioroute; | 829 | route.input = core->board.radio.audioroute; |
835 | cx88_call_i2c_clients(core, | 830 | cx88_call_i2c_clients(core, |
836 | VIDIOC_INT_S_AUDIO_ROUTING, &route); | 831 | VIDIOC_INT_S_AUDIO_ROUTING, &route); |
837 | } | 832 | } |
838 | /* "I2S ADC mode" */ | 833 | /* "I2S ADC mode" */ |
839 | core->tvaudio = WW_I2SADC; | 834 | core->tvaudio = WW_I2SADC; |
840 | cx88_set_tvaudio(core); | 835 | cx88_set_tvaudio(core); |
841 | } else { | 836 | } else { |
842 | /* FM Mode */ | 837 | /* FM Mode */ |
843 | core->tvaudio = WW_FM; | 838 | core->tvaudio = WW_FM; |
844 | cx88_set_tvaudio(core); | 839 | cx88_set_tvaudio(core); |
845 | cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); | 840 | cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); |
846 | } | 841 | } |
847 | cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); | 842 | cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); |
848 | } | 843 | } |
849 | unlock_kernel(); | 844 | unlock_kernel(); |
850 | 845 | ||
851 | atomic_inc(&core->users); | 846 | atomic_inc(&core->users); |
852 | 847 | ||
853 | return 0; | 848 | return 0; |
854 | } | 849 | } |
855 | 850 | ||
856 | static ssize_t | 851 | static ssize_t |
857 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 852 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
858 | { | 853 | { |
859 | struct cx8800_fh *fh = file->private_data; | 854 | struct cx8800_fh *fh = file->private_data; |
860 | 855 | ||
861 | switch (fh->type) { | 856 | switch (fh->type) { |
862 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 857 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
863 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | 858 | if (res_locked(fh->dev,RESOURCE_VIDEO)) |
864 | return -EBUSY; | 859 | return -EBUSY; |
865 | return videobuf_read_one(&fh->vidq, data, count, ppos, | 860 | return videobuf_read_one(&fh->vidq, data, count, ppos, |
866 | file->f_flags & O_NONBLOCK); | 861 | file->f_flags & O_NONBLOCK); |
867 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 862 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
868 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | 863 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) |
869 | return -EBUSY; | 864 | return -EBUSY; |
870 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, | 865 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, |
871 | file->f_flags & O_NONBLOCK); | 866 | file->f_flags & O_NONBLOCK); |
872 | default: | 867 | default: |
873 | BUG(); | 868 | BUG(); |
874 | return 0; | 869 | return 0; |
875 | } | 870 | } |
876 | } | 871 | } |
877 | 872 | ||
878 | static unsigned int | 873 | static unsigned int |
879 | video_poll(struct file *file, struct poll_table_struct *wait) | 874 | video_poll(struct file *file, struct poll_table_struct *wait) |
880 | { | 875 | { |
881 | struct cx8800_fh *fh = file->private_data; | 876 | struct cx8800_fh *fh = file->private_data; |
882 | struct cx88_buffer *buf; | 877 | struct cx88_buffer *buf; |
883 | 878 | ||
884 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | 879 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { |
885 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | 880 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) |
886 | return POLLERR; | 881 | return POLLERR; |
887 | return videobuf_poll_stream(file, &fh->vbiq, wait); | 882 | return videobuf_poll_stream(file, &fh->vbiq, wait); |
888 | } | 883 | } |
889 | 884 | ||
890 | if (res_check(fh,RESOURCE_VIDEO)) { | 885 | if (res_check(fh,RESOURCE_VIDEO)) { |
891 | /* streaming capture */ | 886 | /* streaming capture */ |
892 | if (list_empty(&fh->vidq.stream)) | 887 | if (list_empty(&fh->vidq.stream)) |
893 | return POLLERR; | 888 | return POLLERR; |
894 | buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); | 889 | buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); |
895 | } else { | 890 | } else { |
896 | /* read() capture */ | 891 | /* read() capture */ |
897 | buf = (struct cx88_buffer*)fh->vidq.read_buf; | 892 | buf = (struct cx88_buffer*)fh->vidq.read_buf; |
898 | if (NULL == buf) | 893 | if (NULL == buf) |
899 | return POLLERR; | 894 | return POLLERR; |
900 | } | 895 | } |
901 | poll_wait(file, &buf->vb.done, wait); | 896 | poll_wait(file, &buf->vb.done, wait); |
902 | if (buf->vb.state == VIDEOBUF_DONE || | 897 | if (buf->vb.state == VIDEOBUF_DONE || |
903 | buf->vb.state == VIDEOBUF_ERROR) | 898 | buf->vb.state == VIDEOBUF_ERROR) |
904 | return POLLIN|POLLRDNORM; | 899 | return POLLIN|POLLRDNORM; |
905 | return 0; | 900 | return 0; |
906 | } | 901 | } |
907 | 902 | ||
908 | static int video_release(struct file *file) | 903 | static int video_release(struct file *file) |
909 | { | 904 | { |
910 | struct cx8800_fh *fh = file->private_data; | 905 | struct cx8800_fh *fh = file->private_data; |
911 | struct cx8800_dev *dev = fh->dev; | 906 | struct cx8800_dev *dev = fh->dev; |
912 | 907 | ||
913 | /* turn off overlay */ | 908 | /* turn off overlay */ |
914 | if (res_check(fh, RESOURCE_OVERLAY)) { | 909 | if (res_check(fh, RESOURCE_OVERLAY)) { |
915 | /* FIXME */ | 910 | /* FIXME */ |
916 | res_free(dev,fh,RESOURCE_OVERLAY); | 911 | res_free(dev,fh,RESOURCE_OVERLAY); |
917 | } | 912 | } |
918 | 913 | ||
919 | /* stop video capture */ | 914 | /* stop video capture */ |
920 | if (res_check(fh, RESOURCE_VIDEO)) { | 915 | if (res_check(fh, RESOURCE_VIDEO)) { |
921 | videobuf_queue_cancel(&fh->vidq); | 916 | videobuf_queue_cancel(&fh->vidq); |
922 | res_free(dev,fh,RESOURCE_VIDEO); | 917 | res_free(dev,fh,RESOURCE_VIDEO); |
923 | } | 918 | } |
924 | if (fh->vidq.read_buf) { | 919 | if (fh->vidq.read_buf) { |
925 | buffer_release(&fh->vidq,fh->vidq.read_buf); | 920 | buffer_release(&fh->vidq,fh->vidq.read_buf); |
926 | kfree(fh->vidq.read_buf); | 921 | kfree(fh->vidq.read_buf); |
927 | } | 922 | } |
928 | 923 | ||
929 | /* stop vbi capture */ | 924 | /* stop vbi capture */ |
930 | if (res_check(fh, RESOURCE_VBI)) { | 925 | if (res_check(fh, RESOURCE_VBI)) { |
931 | videobuf_stop(&fh->vbiq); | 926 | videobuf_stop(&fh->vbiq); |
932 | res_free(dev,fh,RESOURCE_VBI); | 927 | res_free(dev,fh,RESOURCE_VBI); |
933 | } | 928 | } |
934 | 929 | ||
935 | videobuf_mmap_free(&fh->vidq); | 930 | videobuf_mmap_free(&fh->vidq); |
936 | videobuf_mmap_free(&fh->vbiq); | 931 | videobuf_mmap_free(&fh->vbiq); |
937 | file->private_data = NULL; | 932 | file->private_data = NULL; |
938 | kfree(fh); | 933 | kfree(fh); |
939 | 934 | ||
940 | if(atomic_dec_and_test(&dev->core->users)) | 935 | if(atomic_dec_and_test(&dev->core->users)) |
941 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); | 936 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); |
942 | 937 | ||
943 | return 0; | 938 | return 0; |
944 | } | 939 | } |
945 | 940 | ||
946 | static int | 941 | static int |
947 | video_mmap(struct file *file, struct vm_area_struct * vma) | 942 | video_mmap(struct file *file, struct vm_area_struct * vma) |
948 | { | 943 | { |
949 | struct cx8800_fh *fh = file->private_data; | 944 | struct cx8800_fh *fh = file->private_data; |
950 | 945 | ||
951 | return videobuf_mmap_mapper(get_queue(fh), vma); | 946 | return videobuf_mmap_mapper(get_queue(fh), vma); |
952 | } | 947 | } |
953 | 948 | ||
954 | /* ------------------------------------------------------------------ */ | 949 | /* ------------------------------------------------------------------ */ |
955 | /* VIDEO CTRL IOCTLS */ | 950 | /* VIDEO CTRL IOCTLS */ |
956 | 951 | ||
957 | int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) | 952 | int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) |
958 | { | 953 | { |
959 | struct cx88_ctrl *c = NULL; | 954 | struct cx88_ctrl *c = NULL; |
960 | u32 value; | 955 | u32 value; |
961 | int i; | 956 | int i; |
962 | 957 | ||
963 | for (i = 0; i < CX8800_CTLS; i++) | 958 | for (i = 0; i < CX8800_CTLS; i++) |
964 | if (cx8800_ctls[i].v.id == ctl->id) | 959 | if (cx8800_ctls[i].v.id == ctl->id) |
965 | c = &cx8800_ctls[i]; | 960 | c = &cx8800_ctls[i]; |
966 | if (unlikely(NULL == c)) | 961 | if (unlikely(NULL == c)) |
967 | return -EINVAL; | 962 | return -EINVAL; |
968 | 963 | ||
969 | value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); | 964 | value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); |
970 | switch (ctl->id) { | 965 | switch (ctl->id) { |
971 | case V4L2_CID_AUDIO_BALANCE: | 966 | case V4L2_CID_AUDIO_BALANCE: |
972 | ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) | 967 | ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) |
973 | : (0x7f - (value & 0x7f)); | 968 | : (0x7f - (value & 0x7f)); |
974 | break; | 969 | break; |
975 | case V4L2_CID_AUDIO_VOLUME: | 970 | case V4L2_CID_AUDIO_VOLUME: |
976 | ctl->value = 0x3f - (value & 0x3f); | 971 | ctl->value = 0x3f - (value & 0x3f); |
977 | break; | 972 | break; |
978 | default: | 973 | default: |
979 | ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; | 974 | ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; |
980 | break; | 975 | break; |
981 | } | 976 | } |
982 | dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", | 977 | dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", |
983 | ctl->id, c->v.name, ctl->value, c->reg, | 978 | ctl->id, c->v.name, ctl->value, c->reg, |
984 | value,c->mask, c->sreg ? " [shadowed]" : ""); | 979 | value,c->mask, c->sreg ? " [shadowed]" : ""); |
985 | return 0; | 980 | return 0; |
986 | } | 981 | } |
987 | EXPORT_SYMBOL(cx88_get_control); | 982 | EXPORT_SYMBOL(cx88_get_control); |
988 | 983 | ||
989 | int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) | 984 | int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) |
990 | { | 985 | { |
991 | struct cx88_ctrl *c = NULL; | 986 | struct cx88_ctrl *c = NULL; |
992 | u32 value,mask; | 987 | u32 value,mask; |
993 | int i; | 988 | int i; |
994 | 989 | ||
995 | for (i = 0; i < CX8800_CTLS; i++) { | 990 | for (i = 0; i < CX8800_CTLS; i++) { |
996 | if (cx8800_ctls[i].v.id == ctl->id) { | 991 | if (cx8800_ctls[i].v.id == ctl->id) { |
997 | c = &cx8800_ctls[i]; | 992 | c = &cx8800_ctls[i]; |
998 | } | 993 | } |
999 | } | 994 | } |
1000 | if (unlikely(NULL == c)) | 995 | if (unlikely(NULL == c)) |
1001 | return -EINVAL; | 996 | return -EINVAL; |
1002 | 997 | ||
1003 | if (ctl->value < c->v.minimum) | 998 | if (ctl->value < c->v.minimum) |
1004 | ctl->value = c->v.minimum; | 999 | ctl->value = c->v.minimum; |
1005 | if (ctl->value > c->v.maximum) | 1000 | if (ctl->value > c->v.maximum) |
1006 | ctl->value = c->v.maximum; | 1001 | ctl->value = c->v.maximum; |
1007 | mask=c->mask; | 1002 | mask=c->mask; |
1008 | switch (ctl->id) { | 1003 | switch (ctl->id) { |
1009 | case V4L2_CID_AUDIO_BALANCE: | 1004 | case V4L2_CID_AUDIO_BALANCE: |
1010 | value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); | 1005 | value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); |
1011 | break; | 1006 | break; |
1012 | case V4L2_CID_AUDIO_VOLUME: | 1007 | case V4L2_CID_AUDIO_VOLUME: |
1013 | value = 0x3f - (ctl->value & 0x3f); | 1008 | value = 0x3f - (ctl->value & 0x3f); |
1014 | break; | 1009 | break; |
1015 | case V4L2_CID_SATURATION: | 1010 | case V4L2_CID_SATURATION: |
1016 | /* special v_sat handling */ | 1011 | /* special v_sat handling */ |
1017 | 1012 | ||
1018 | value = ((ctl->value - c->off) << c->shift) & c->mask; | 1013 | value = ((ctl->value - c->off) << c->shift) & c->mask; |
1019 | 1014 | ||
1020 | if (core->tvnorm & V4L2_STD_SECAM) { | 1015 | if (core->tvnorm & V4L2_STD_SECAM) { |
1021 | /* For SECAM, both U and V sat should be equal */ | 1016 | /* For SECAM, both U and V sat should be equal */ |
1022 | value=value<<8|value; | 1017 | value=value<<8|value; |
1023 | } else { | 1018 | } else { |
1024 | /* Keeps U Saturation proportional to V Sat */ | 1019 | /* Keeps U Saturation proportional to V Sat */ |
1025 | value=(value*0x5a)/0x7f<<8|value; | 1020 | value=(value*0x5a)/0x7f<<8|value; |
1026 | } | 1021 | } |
1027 | mask=0xffff; | 1022 | mask=0xffff; |
1028 | break; | 1023 | break; |
1029 | case V4L2_CID_CHROMA_AGC: | 1024 | case V4L2_CID_CHROMA_AGC: |
1030 | /* Do not allow chroma AGC to be enabled for SECAM */ | 1025 | /* Do not allow chroma AGC to be enabled for SECAM */ |
1031 | value = ((ctl->value - c->off) << c->shift) & c->mask; | 1026 | value = ((ctl->value - c->off) << c->shift) & c->mask; |
1032 | if (core->tvnorm & V4L2_STD_SECAM && value) | 1027 | if (core->tvnorm & V4L2_STD_SECAM && value) |
1033 | return -EINVAL; | 1028 | return -EINVAL; |
1034 | break; | 1029 | break; |
1035 | default: | 1030 | default: |
1036 | value = ((ctl->value - c->off) << c->shift) & c->mask; | 1031 | value = ((ctl->value - c->off) << c->shift) & c->mask; |
1037 | break; | 1032 | break; |
1038 | } | 1033 | } |
1039 | dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", | 1034 | dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", |
1040 | ctl->id, c->v.name, ctl->value, c->reg, value, | 1035 | ctl->id, c->v.name, ctl->value, c->reg, value, |
1041 | mask, c->sreg ? " [shadowed]" : ""); | 1036 | mask, c->sreg ? " [shadowed]" : ""); |
1042 | if (c->sreg) { | 1037 | if (c->sreg) { |
1043 | cx_sandor(c->sreg, c->reg, mask, value); | 1038 | cx_sandor(c->sreg, c->reg, mask, value); |
1044 | } else { | 1039 | } else { |
1045 | cx_andor(c->reg, mask, value); | 1040 | cx_andor(c->reg, mask, value); |
1046 | } | 1041 | } |
1047 | return 0; | 1042 | return 0; |
1048 | } | 1043 | } |
1049 | EXPORT_SYMBOL(cx88_set_control); | 1044 | EXPORT_SYMBOL(cx88_set_control); |
1050 | 1045 | ||
1051 | static void init_controls(struct cx88_core *core) | 1046 | static void init_controls(struct cx88_core *core) |
1052 | { | 1047 | { |
1053 | struct v4l2_control ctrl; | 1048 | struct v4l2_control ctrl; |
1054 | int i; | 1049 | int i; |
1055 | 1050 | ||
1056 | for (i = 0; i < CX8800_CTLS; i++) { | 1051 | for (i = 0; i < CX8800_CTLS; i++) { |
1057 | ctrl.id=cx8800_ctls[i].v.id; | 1052 | ctrl.id=cx8800_ctls[i].v.id; |
1058 | ctrl.value=cx8800_ctls[i].v.default_value; | 1053 | ctrl.value=cx8800_ctls[i].v.default_value; |
1059 | 1054 | ||
1060 | cx88_set_control(core, &ctrl); | 1055 | cx88_set_control(core, &ctrl); |
1061 | } | 1056 | } |
1062 | } | 1057 | } |
1063 | 1058 | ||
1064 | /* ------------------------------------------------------------------ */ | 1059 | /* ------------------------------------------------------------------ */ |
1065 | /* VIDEO IOCTLS */ | 1060 | /* VIDEO IOCTLS */ |
1066 | 1061 | ||
1067 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | 1062 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
1068 | struct v4l2_format *f) | 1063 | struct v4l2_format *f) |
1069 | { | 1064 | { |
1070 | struct cx8800_fh *fh = priv; | 1065 | struct cx8800_fh *fh = priv; |
1071 | 1066 | ||
1072 | f->fmt.pix.width = fh->width; | 1067 | f->fmt.pix.width = fh->width; |
1073 | f->fmt.pix.height = fh->height; | 1068 | f->fmt.pix.height = fh->height; |
1074 | f->fmt.pix.field = fh->vidq.field; | 1069 | f->fmt.pix.field = fh->vidq.field; |
1075 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | 1070 | f->fmt.pix.pixelformat = fh->fmt->fourcc; |
1076 | f->fmt.pix.bytesperline = | 1071 | f->fmt.pix.bytesperline = |
1077 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | 1072 | (f->fmt.pix.width * fh->fmt->depth) >> 3; |
1078 | f->fmt.pix.sizeimage = | 1073 | f->fmt.pix.sizeimage = |
1079 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1074 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1080 | return 0; | 1075 | return 0; |
1081 | } | 1076 | } |
1082 | 1077 | ||
1083 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | 1078 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
1084 | struct v4l2_format *f) | 1079 | struct v4l2_format *f) |
1085 | { | 1080 | { |
1086 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1081 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1087 | struct cx8800_fmt *fmt; | 1082 | struct cx8800_fmt *fmt; |
1088 | enum v4l2_field field; | 1083 | enum v4l2_field field; |
1089 | unsigned int maxw, maxh; | 1084 | unsigned int maxw, maxh; |
1090 | 1085 | ||
1091 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1086 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1092 | if (NULL == fmt) | 1087 | if (NULL == fmt) |
1093 | return -EINVAL; | 1088 | return -EINVAL; |
1094 | 1089 | ||
1095 | field = f->fmt.pix.field; | 1090 | field = f->fmt.pix.field; |
1096 | maxw = norm_maxw(core->tvnorm); | 1091 | maxw = norm_maxw(core->tvnorm); |
1097 | maxh = norm_maxh(core->tvnorm); | 1092 | maxh = norm_maxh(core->tvnorm); |
1098 | 1093 | ||
1099 | if (V4L2_FIELD_ANY == field) { | 1094 | if (V4L2_FIELD_ANY == field) { |
1100 | field = (f->fmt.pix.height > maxh/2) | 1095 | field = (f->fmt.pix.height > maxh/2) |
1101 | ? V4L2_FIELD_INTERLACED | 1096 | ? V4L2_FIELD_INTERLACED |
1102 | : V4L2_FIELD_BOTTOM; | 1097 | : V4L2_FIELD_BOTTOM; |
1103 | } | 1098 | } |
1104 | 1099 | ||
1105 | switch (field) { | 1100 | switch (field) { |
1106 | case V4L2_FIELD_TOP: | 1101 | case V4L2_FIELD_TOP: |
1107 | case V4L2_FIELD_BOTTOM: | 1102 | case V4L2_FIELD_BOTTOM: |
1108 | maxh = maxh / 2; | 1103 | maxh = maxh / 2; |
1109 | break; | 1104 | break; |
1110 | case V4L2_FIELD_INTERLACED: | 1105 | case V4L2_FIELD_INTERLACED: |
1111 | break; | 1106 | break; |
1112 | default: | 1107 | default: |
1113 | return -EINVAL; | 1108 | return -EINVAL; |
1114 | } | 1109 | } |
1115 | 1110 | ||
1116 | f->fmt.pix.field = field; | 1111 | f->fmt.pix.field = field; |
1117 | if (f->fmt.pix.height < 32) | 1112 | if (f->fmt.pix.height < 32) |
1118 | f->fmt.pix.height = 32; | 1113 | f->fmt.pix.height = 32; |
1119 | if (f->fmt.pix.height > maxh) | 1114 | if (f->fmt.pix.height > maxh) |
1120 | f->fmt.pix.height = maxh; | 1115 | f->fmt.pix.height = maxh; |
1121 | if (f->fmt.pix.width < 48) | 1116 | if (f->fmt.pix.width < 48) |
1122 | f->fmt.pix.width = 48; | 1117 | f->fmt.pix.width = 48; |
1123 | if (f->fmt.pix.width > maxw) | 1118 | if (f->fmt.pix.width > maxw) |
1124 | f->fmt.pix.width = maxw; | 1119 | f->fmt.pix.width = maxw; |
1125 | f->fmt.pix.width &= ~0x03; | 1120 | f->fmt.pix.width &= ~0x03; |
1126 | f->fmt.pix.bytesperline = | 1121 | f->fmt.pix.bytesperline = |
1127 | (f->fmt.pix.width * fmt->depth) >> 3; | 1122 | (f->fmt.pix.width * fmt->depth) >> 3; |
1128 | f->fmt.pix.sizeimage = | 1123 | f->fmt.pix.sizeimage = |
1129 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1124 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1130 | 1125 | ||
1131 | return 0; | 1126 | return 0; |
1132 | } | 1127 | } |
1133 | 1128 | ||
1134 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 1129 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
1135 | struct v4l2_format *f) | 1130 | struct v4l2_format *f) |
1136 | { | 1131 | { |
1137 | struct cx8800_fh *fh = priv; | 1132 | struct cx8800_fh *fh = priv; |
1138 | int err = vidioc_try_fmt_vid_cap (file,priv,f); | 1133 | int err = vidioc_try_fmt_vid_cap (file,priv,f); |
1139 | 1134 | ||
1140 | if (0 != err) | 1135 | if (0 != err) |
1141 | return err; | 1136 | return err; |
1142 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1137 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1143 | fh->width = f->fmt.pix.width; | 1138 | fh->width = f->fmt.pix.width; |
1144 | fh->height = f->fmt.pix.height; | 1139 | fh->height = f->fmt.pix.height; |
1145 | fh->vidq.field = f->fmt.pix.field; | 1140 | fh->vidq.field = f->fmt.pix.field; |
1146 | return 0; | 1141 | return 0; |
1147 | } | 1142 | } |
1148 | 1143 | ||
1149 | static int vidioc_querycap (struct file *file, void *priv, | 1144 | static int vidioc_querycap (struct file *file, void *priv, |
1150 | struct v4l2_capability *cap) | 1145 | struct v4l2_capability *cap) |
1151 | { | 1146 | { |
1152 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; | 1147 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; |
1153 | struct cx88_core *core = dev->core; | 1148 | struct cx88_core *core = dev->core; |
1154 | 1149 | ||
1155 | strcpy(cap->driver, "cx8800"); | 1150 | strcpy(cap->driver, "cx8800"); |
1156 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); | 1151 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); |
1157 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | 1152 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); |
1158 | cap->version = CX88_VERSION_CODE; | 1153 | cap->version = CX88_VERSION_CODE; |
1159 | cap->capabilities = | 1154 | cap->capabilities = |
1160 | V4L2_CAP_VIDEO_CAPTURE | | 1155 | V4L2_CAP_VIDEO_CAPTURE | |
1161 | V4L2_CAP_READWRITE | | 1156 | V4L2_CAP_READWRITE | |
1162 | V4L2_CAP_STREAMING | | 1157 | V4L2_CAP_STREAMING | |
1163 | V4L2_CAP_VBI_CAPTURE; | 1158 | V4L2_CAP_VBI_CAPTURE; |
1164 | if (UNSET != core->board.tuner_type) | 1159 | if (UNSET != core->board.tuner_type) |
1165 | cap->capabilities |= V4L2_CAP_TUNER; | 1160 | cap->capabilities |= V4L2_CAP_TUNER; |
1166 | return 0; | 1161 | return 0; |
1167 | } | 1162 | } |
1168 | 1163 | ||
1169 | static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, | 1164 | static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, |
1170 | struct v4l2_fmtdesc *f) | 1165 | struct v4l2_fmtdesc *f) |
1171 | { | 1166 | { |
1172 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | 1167 | if (unlikely(f->index >= ARRAY_SIZE(formats))) |
1173 | return -EINVAL; | 1168 | return -EINVAL; |
1174 | 1169 | ||
1175 | strlcpy(f->description,formats[f->index].name,sizeof(f->description)); | 1170 | strlcpy(f->description,formats[f->index].name,sizeof(f->description)); |
1176 | f->pixelformat = formats[f->index].fourcc; | 1171 | f->pixelformat = formats[f->index].fourcc; |
1177 | 1172 | ||
1178 | return 0; | 1173 | return 0; |
1179 | } | 1174 | } |
1180 | 1175 | ||
1181 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1176 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1182 | static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) | 1177 | static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) |
1183 | { | 1178 | { |
1184 | struct cx8800_fh *fh = priv; | 1179 | struct cx8800_fh *fh = priv; |
1185 | 1180 | ||
1186 | return videobuf_cgmbuf (get_queue(fh), mbuf, 8); | 1181 | return videobuf_cgmbuf (get_queue(fh), mbuf, 8); |
1187 | } | 1182 | } |
1188 | #endif | 1183 | #endif |
1189 | 1184 | ||
1190 | static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) | 1185 | static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) |
1191 | { | 1186 | { |
1192 | struct cx8800_fh *fh = priv; | 1187 | struct cx8800_fh *fh = priv; |
1193 | return (videobuf_reqbufs(get_queue(fh), p)); | 1188 | return (videobuf_reqbufs(get_queue(fh), p)); |
1194 | } | 1189 | } |
1195 | 1190 | ||
1196 | static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) | 1191 | static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1197 | { | 1192 | { |
1198 | struct cx8800_fh *fh = priv; | 1193 | struct cx8800_fh *fh = priv; |
1199 | return (videobuf_querybuf(get_queue(fh), p)); | 1194 | return (videobuf_querybuf(get_queue(fh), p)); |
1200 | } | 1195 | } |
1201 | 1196 | ||
1202 | static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) | 1197 | static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1203 | { | 1198 | { |
1204 | struct cx8800_fh *fh = priv; | 1199 | struct cx8800_fh *fh = priv; |
1205 | return (videobuf_qbuf(get_queue(fh), p)); | 1200 | return (videobuf_qbuf(get_queue(fh), p)); |
1206 | } | 1201 | } |
1207 | 1202 | ||
1208 | static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) | 1203 | static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1209 | { | 1204 | { |
1210 | struct cx8800_fh *fh = priv; | 1205 | struct cx8800_fh *fh = priv; |
1211 | return (videobuf_dqbuf(get_queue(fh), p, | 1206 | return (videobuf_dqbuf(get_queue(fh), p, |
1212 | file->f_flags & O_NONBLOCK)); | 1207 | file->f_flags & O_NONBLOCK)); |
1213 | } | 1208 | } |
1214 | 1209 | ||
1215 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | 1210 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
1216 | { | 1211 | { |
1217 | struct cx8800_fh *fh = priv; | 1212 | struct cx8800_fh *fh = priv; |
1218 | struct cx8800_dev *dev = fh->dev; | 1213 | struct cx8800_dev *dev = fh->dev; |
1219 | 1214 | ||
1220 | /* We should remember that this driver also supports teletext, */ | 1215 | /* We should remember that this driver also supports teletext, */ |
1221 | /* so we have to test if the v4l2_buf_type is VBI capture data. */ | 1216 | /* so we have to test if the v4l2_buf_type is VBI capture data. */ |
1222 | if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 1217 | if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
1223 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) | 1218 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) |
1224 | return -EINVAL; | 1219 | return -EINVAL; |
1225 | 1220 | ||
1226 | if (unlikely(i != fh->type)) | 1221 | if (unlikely(i != fh->type)) |
1227 | return -EINVAL; | 1222 | return -EINVAL; |
1228 | 1223 | ||
1229 | if (unlikely(!res_get(dev,fh,get_ressource(fh)))) | 1224 | if (unlikely(!res_get(dev,fh,get_ressource(fh)))) |
1230 | return -EBUSY; | 1225 | return -EBUSY; |
1231 | return videobuf_streamon(get_queue(fh)); | 1226 | return videobuf_streamon(get_queue(fh)); |
1232 | } | 1227 | } |
1233 | 1228 | ||
1234 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | 1229 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
1235 | { | 1230 | { |
1236 | struct cx8800_fh *fh = priv; | 1231 | struct cx8800_fh *fh = priv; |
1237 | struct cx8800_dev *dev = fh->dev; | 1232 | struct cx8800_dev *dev = fh->dev; |
1238 | int err, res; | 1233 | int err, res; |
1239 | 1234 | ||
1240 | if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 1235 | if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
1241 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 1236 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
1242 | return -EINVAL; | 1237 | return -EINVAL; |
1243 | 1238 | ||
1244 | if (i != fh->type) | 1239 | if (i != fh->type) |
1245 | return -EINVAL; | 1240 | return -EINVAL; |
1246 | 1241 | ||
1247 | res = get_ressource(fh); | 1242 | res = get_ressource(fh); |
1248 | err = videobuf_streamoff(get_queue(fh)); | 1243 | err = videobuf_streamoff(get_queue(fh)); |
1249 | if (err < 0) | 1244 | if (err < 0) |
1250 | return err; | 1245 | return err; |
1251 | res_free(dev,fh,res); | 1246 | res_free(dev,fh,res); |
1252 | return 0; | 1247 | return 0; |
1253 | } | 1248 | } |
1254 | 1249 | ||
1255 | static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) | 1250 | static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) |
1256 | { | 1251 | { |
1257 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1252 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1258 | 1253 | ||
1259 | mutex_lock(&core->lock); | 1254 | mutex_lock(&core->lock); |
1260 | cx88_set_tvnorm(core,*tvnorms); | 1255 | cx88_set_tvnorm(core,*tvnorms); |
1261 | mutex_unlock(&core->lock); | 1256 | mutex_unlock(&core->lock); |
1262 | 1257 | ||
1263 | return 0; | 1258 | return 0; |
1264 | } | 1259 | } |
1265 | 1260 | ||
1266 | /* only one input in this sample driver */ | 1261 | /* only one input in this sample driver */ |
1267 | int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) | 1262 | int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) |
1268 | { | 1263 | { |
1269 | static const char *iname[] = { | 1264 | static const char *iname[] = { |
1270 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", | 1265 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", |
1271 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", | 1266 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", |
1272 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", | 1267 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", |
1273 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", | 1268 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", |
1274 | [ CX88_VMUX_SVIDEO ] = "S-Video", | 1269 | [ CX88_VMUX_SVIDEO ] = "S-Video", |
1275 | [ CX88_VMUX_TELEVISION ] = "Television", | 1270 | [ CX88_VMUX_TELEVISION ] = "Television", |
1276 | [ CX88_VMUX_CABLE ] = "Cable TV", | 1271 | [ CX88_VMUX_CABLE ] = "Cable TV", |
1277 | [ CX88_VMUX_DVB ] = "DVB", | 1272 | [ CX88_VMUX_DVB ] = "DVB", |
1278 | [ CX88_VMUX_DEBUG ] = "for debug only", | 1273 | [ CX88_VMUX_DEBUG ] = "for debug only", |
1279 | }; | 1274 | }; |
1280 | unsigned int n = i->index; | 1275 | unsigned int n = i->index; |
1281 | 1276 | ||
1282 | if (n >= 4) | 1277 | if (n >= 4) |
1283 | return -EINVAL; | 1278 | return -EINVAL; |
1284 | if (0 == INPUT(n).type) | 1279 | if (0 == INPUT(n).type) |
1285 | return -EINVAL; | 1280 | return -EINVAL; |
1286 | i->type = V4L2_INPUT_TYPE_CAMERA; | 1281 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1287 | strcpy(i->name,iname[INPUT(n).type]); | 1282 | strcpy(i->name,iname[INPUT(n).type]); |
1288 | if ((CX88_VMUX_TELEVISION == INPUT(n).type) || | 1283 | if ((CX88_VMUX_TELEVISION == INPUT(n).type) || |
1289 | (CX88_VMUX_CABLE == INPUT(n).type)) | 1284 | (CX88_VMUX_CABLE == INPUT(n).type)) |
1290 | i->type = V4L2_INPUT_TYPE_TUNER; | 1285 | i->type = V4L2_INPUT_TYPE_TUNER; |
1291 | i->std = CX88_NORMS; | 1286 | i->std = CX88_NORMS; |
1292 | return 0; | 1287 | return 0; |
1293 | } | 1288 | } |
1294 | EXPORT_SYMBOL(cx88_enum_input); | 1289 | EXPORT_SYMBOL(cx88_enum_input); |
1295 | 1290 | ||
1296 | static int vidioc_enum_input (struct file *file, void *priv, | 1291 | static int vidioc_enum_input (struct file *file, void *priv, |
1297 | struct v4l2_input *i) | 1292 | struct v4l2_input *i) |
1298 | { | 1293 | { |
1299 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1294 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1300 | return cx88_enum_input (core,i); | 1295 | return cx88_enum_input (core,i); |
1301 | } | 1296 | } |
1302 | 1297 | ||
1303 | static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) | 1298 | static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) |
1304 | { | 1299 | { |
1305 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1300 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1306 | 1301 | ||
1307 | *i = core->input; | 1302 | *i = core->input; |
1308 | return 0; | 1303 | return 0; |
1309 | } | 1304 | } |
1310 | 1305 | ||
1311 | static int vidioc_s_input (struct file *file, void *priv, unsigned int i) | 1306 | static int vidioc_s_input (struct file *file, void *priv, unsigned int i) |
1312 | { | 1307 | { |
1313 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1308 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1314 | 1309 | ||
1315 | if (i >= 4) | 1310 | if (i >= 4) |
1316 | return -EINVAL; | 1311 | return -EINVAL; |
1317 | 1312 | ||
1318 | mutex_lock(&core->lock); | 1313 | mutex_lock(&core->lock); |
1319 | cx88_newstation(core); | 1314 | cx88_newstation(core); |
1320 | cx88_video_mux(core,i); | 1315 | cx88_video_mux(core,i); |
1321 | mutex_unlock(&core->lock); | 1316 | mutex_unlock(&core->lock); |
1322 | return 0; | 1317 | return 0; |
1323 | } | 1318 | } |
1324 | 1319 | ||
1325 | 1320 | ||
1326 | 1321 | ||
1327 | static int vidioc_queryctrl (struct file *file, void *priv, | 1322 | static int vidioc_queryctrl (struct file *file, void *priv, |
1328 | struct v4l2_queryctrl *qctrl) | 1323 | struct v4l2_queryctrl *qctrl) |
1329 | { | 1324 | { |
1330 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1325 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1331 | 1326 | ||
1332 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | 1327 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); |
1333 | if (unlikely(qctrl->id == 0)) | 1328 | if (unlikely(qctrl->id == 0)) |
1334 | return -EINVAL; | 1329 | return -EINVAL; |
1335 | return cx8800_ctrl_query(core, qctrl); | 1330 | return cx8800_ctrl_query(core, qctrl); |
1336 | } | 1331 | } |
1337 | 1332 | ||
1338 | static int vidioc_g_ctrl (struct file *file, void *priv, | 1333 | static int vidioc_g_ctrl (struct file *file, void *priv, |
1339 | struct v4l2_control *ctl) | 1334 | struct v4l2_control *ctl) |
1340 | { | 1335 | { |
1341 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1336 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1342 | return | 1337 | return |
1343 | cx88_get_control(core,ctl); | 1338 | cx88_get_control(core,ctl); |
1344 | } | 1339 | } |
1345 | 1340 | ||
1346 | static int vidioc_s_ctrl (struct file *file, void *priv, | 1341 | static int vidioc_s_ctrl (struct file *file, void *priv, |
1347 | struct v4l2_control *ctl) | 1342 | struct v4l2_control *ctl) |
1348 | { | 1343 | { |
1349 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1344 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1350 | return | 1345 | return |
1351 | cx88_set_control(core,ctl); | 1346 | cx88_set_control(core,ctl); |
1352 | } | 1347 | } |
1353 | 1348 | ||
1354 | static int vidioc_g_tuner (struct file *file, void *priv, | 1349 | static int vidioc_g_tuner (struct file *file, void *priv, |
1355 | struct v4l2_tuner *t) | 1350 | struct v4l2_tuner *t) |
1356 | { | 1351 | { |
1357 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1352 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1358 | u32 reg; | 1353 | u32 reg; |
1359 | 1354 | ||
1360 | if (unlikely(UNSET == core->board.tuner_type)) | 1355 | if (unlikely(UNSET == core->board.tuner_type)) |
1361 | return -EINVAL; | 1356 | return -EINVAL; |
1362 | if (0 != t->index) | 1357 | if (0 != t->index) |
1363 | return -EINVAL; | 1358 | return -EINVAL; |
1364 | 1359 | ||
1365 | strcpy(t->name, "Television"); | 1360 | strcpy(t->name, "Television"); |
1366 | t->type = V4L2_TUNER_ANALOG_TV; | 1361 | t->type = V4L2_TUNER_ANALOG_TV; |
1367 | t->capability = V4L2_TUNER_CAP_NORM; | 1362 | t->capability = V4L2_TUNER_CAP_NORM; |
1368 | t->rangehigh = 0xffffffffUL; | 1363 | t->rangehigh = 0xffffffffUL; |
1369 | 1364 | ||
1370 | cx88_get_stereo(core ,t); | 1365 | cx88_get_stereo(core ,t); |
1371 | reg = cx_read(MO_DEVICE_STATUS); | 1366 | reg = cx_read(MO_DEVICE_STATUS); |
1372 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | 1367 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; |
1373 | return 0; | 1368 | return 0; |
1374 | } | 1369 | } |
1375 | 1370 | ||
1376 | static int vidioc_s_tuner (struct file *file, void *priv, | 1371 | static int vidioc_s_tuner (struct file *file, void *priv, |
1377 | struct v4l2_tuner *t) | 1372 | struct v4l2_tuner *t) |
1378 | { | 1373 | { |
1379 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1374 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1380 | 1375 | ||
1381 | if (UNSET == core->board.tuner_type) | 1376 | if (UNSET == core->board.tuner_type) |
1382 | return -EINVAL; | 1377 | return -EINVAL; |
1383 | if (0 != t->index) | 1378 | if (0 != t->index) |
1384 | return -EINVAL; | 1379 | return -EINVAL; |
1385 | 1380 | ||
1386 | cx88_set_stereo(core, t->audmode, 1); | 1381 | cx88_set_stereo(core, t->audmode, 1); |
1387 | return 0; | 1382 | return 0; |
1388 | } | 1383 | } |
1389 | 1384 | ||
1390 | static int vidioc_g_frequency (struct file *file, void *priv, | 1385 | static int vidioc_g_frequency (struct file *file, void *priv, |
1391 | struct v4l2_frequency *f) | 1386 | struct v4l2_frequency *f) |
1392 | { | 1387 | { |
1393 | struct cx8800_fh *fh = priv; | 1388 | struct cx8800_fh *fh = priv; |
1394 | struct cx88_core *core = fh->dev->core; | 1389 | struct cx88_core *core = fh->dev->core; |
1395 | 1390 | ||
1396 | if (unlikely(UNSET == core->board.tuner_type)) | 1391 | if (unlikely(UNSET == core->board.tuner_type)) |
1397 | return -EINVAL; | 1392 | return -EINVAL; |
1398 | 1393 | ||
1399 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | 1394 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ |
1400 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 1395 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; |
1401 | f->frequency = core->freq; | 1396 | f->frequency = core->freq; |
1402 | 1397 | ||
1403 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); | 1398 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); |
1404 | 1399 | ||
1405 | return 0; | 1400 | return 0; |
1406 | } | 1401 | } |
1407 | 1402 | ||
1408 | int cx88_set_freq (struct cx88_core *core, | 1403 | int cx88_set_freq (struct cx88_core *core, |
1409 | struct v4l2_frequency *f) | 1404 | struct v4l2_frequency *f) |
1410 | { | 1405 | { |
1411 | if (unlikely(UNSET == core->board.tuner_type)) | 1406 | if (unlikely(UNSET == core->board.tuner_type)) |
1412 | return -EINVAL; | 1407 | return -EINVAL; |
1413 | if (unlikely(f->tuner != 0)) | 1408 | if (unlikely(f->tuner != 0)) |
1414 | return -EINVAL; | 1409 | return -EINVAL; |
1415 | 1410 | ||
1416 | mutex_lock(&core->lock); | 1411 | mutex_lock(&core->lock); |
1417 | core->freq = f->frequency; | 1412 | core->freq = f->frequency; |
1418 | cx88_newstation(core); | 1413 | cx88_newstation(core); |
1419 | cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); | 1414 | cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); |
1420 | 1415 | ||
1421 | /* When changing channels it is required to reset TVAUDIO */ | 1416 | /* When changing channels it is required to reset TVAUDIO */ |
1422 | msleep (10); | 1417 | msleep (10); |
1423 | cx88_set_tvaudio(core); | 1418 | cx88_set_tvaudio(core); |
1424 | 1419 | ||
1425 | mutex_unlock(&core->lock); | 1420 | mutex_unlock(&core->lock); |
1426 | 1421 | ||
1427 | return 0; | 1422 | return 0; |
1428 | } | 1423 | } |
1429 | EXPORT_SYMBOL(cx88_set_freq); | 1424 | EXPORT_SYMBOL(cx88_set_freq); |
1430 | 1425 | ||
1431 | static int vidioc_s_frequency (struct file *file, void *priv, | 1426 | static int vidioc_s_frequency (struct file *file, void *priv, |
1432 | struct v4l2_frequency *f) | 1427 | struct v4l2_frequency *f) |
1433 | { | 1428 | { |
1434 | struct cx8800_fh *fh = priv; | 1429 | struct cx8800_fh *fh = priv; |
1435 | struct cx88_core *core = fh->dev->core; | 1430 | struct cx88_core *core = fh->dev->core; |
1436 | 1431 | ||
1437 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) | 1432 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) |
1438 | return -EINVAL; | 1433 | return -EINVAL; |
1439 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | 1434 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) |
1440 | return -EINVAL; | 1435 | return -EINVAL; |
1441 | 1436 | ||
1442 | return | 1437 | return |
1443 | cx88_set_freq (core,f); | 1438 | cx88_set_freq (core,f); |
1444 | } | 1439 | } |
1445 | 1440 | ||
1446 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1441 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1447 | static int vidioc_g_register (struct file *file, void *fh, | 1442 | static int vidioc_g_register (struct file *file, void *fh, |
1448 | struct v4l2_dbg_register *reg) | 1443 | struct v4l2_dbg_register *reg) |
1449 | { | 1444 | { |
1450 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; | 1445 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; |
1451 | 1446 | ||
1452 | if (!v4l2_chip_match_host(®->match)) | 1447 | if (!v4l2_chip_match_host(®->match)) |
1453 | return -EINVAL; | 1448 | return -EINVAL; |
1454 | /* cx2388x has a 24-bit register space */ | 1449 | /* cx2388x has a 24-bit register space */ |
1455 | reg->val = cx_read(reg->reg & 0xffffff); | 1450 | reg->val = cx_read(reg->reg & 0xffffff); |
1456 | reg->size = 4; | 1451 | reg->size = 4; |
1457 | return 0; | 1452 | return 0; |
1458 | } | 1453 | } |
1459 | 1454 | ||
1460 | static int vidioc_s_register (struct file *file, void *fh, | 1455 | static int vidioc_s_register (struct file *file, void *fh, |
1461 | struct v4l2_dbg_register *reg) | 1456 | struct v4l2_dbg_register *reg) |
1462 | { | 1457 | { |
1463 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; | 1458 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; |
1464 | 1459 | ||
1465 | if (!v4l2_chip_match_host(®->match)) | 1460 | if (!v4l2_chip_match_host(®->match)) |
1466 | return -EINVAL; | 1461 | return -EINVAL; |
1467 | cx_write(reg->reg & 0xffffff, reg->val); | 1462 | cx_write(reg->reg & 0xffffff, reg->val); |
1468 | return 0; | 1463 | return 0; |
1469 | } | 1464 | } |
1470 | #endif | 1465 | #endif |
1471 | 1466 | ||
1472 | /* ----------------------------------------------------------- */ | 1467 | /* ----------------------------------------------------------- */ |
1473 | /* RADIO ESPECIFIC IOCTLS */ | 1468 | /* RADIO ESPECIFIC IOCTLS */ |
1474 | /* ----------------------------------------------------------- */ | 1469 | /* ----------------------------------------------------------- */ |
1475 | 1470 | ||
1476 | static int radio_querycap (struct file *file, void *priv, | 1471 | static int radio_querycap (struct file *file, void *priv, |
1477 | struct v4l2_capability *cap) | 1472 | struct v4l2_capability *cap) |
1478 | { | 1473 | { |
1479 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; | 1474 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; |
1480 | struct cx88_core *core = dev->core; | 1475 | struct cx88_core *core = dev->core; |
1481 | 1476 | ||
1482 | strcpy(cap->driver, "cx8800"); | 1477 | strcpy(cap->driver, "cx8800"); |
1483 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); | 1478 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); |
1484 | sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); | 1479 | sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); |
1485 | cap->version = CX88_VERSION_CODE; | 1480 | cap->version = CX88_VERSION_CODE; |
1486 | cap->capabilities = V4L2_CAP_TUNER; | 1481 | cap->capabilities = V4L2_CAP_TUNER; |
1487 | return 0; | 1482 | return 0; |
1488 | } | 1483 | } |
1489 | 1484 | ||
1490 | static int radio_g_tuner (struct file *file, void *priv, | 1485 | static int radio_g_tuner (struct file *file, void *priv, |
1491 | struct v4l2_tuner *t) | 1486 | struct v4l2_tuner *t) |
1492 | { | 1487 | { |
1493 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1488 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1494 | 1489 | ||
1495 | if (unlikely(t->index > 0)) | 1490 | if (unlikely(t->index > 0)) |
1496 | return -EINVAL; | 1491 | return -EINVAL; |
1497 | 1492 | ||
1498 | strcpy(t->name, "Radio"); | 1493 | strcpy(t->name, "Radio"); |
1499 | t->type = V4L2_TUNER_RADIO; | 1494 | t->type = V4L2_TUNER_RADIO; |
1500 | 1495 | ||
1501 | cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); | 1496 | cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); |
1502 | return 0; | 1497 | return 0; |
1503 | } | 1498 | } |
1504 | 1499 | ||
1505 | static int radio_enum_input (struct file *file, void *priv, | 1500 | static int radio_enum_input (struct file *file, void *priv, |
1506 | struct v4l2_input *i) | 1501 | struct v4l2_input *i) |
1507 | { | 1502 | { |
1508 | if (i->index != 0) | 1503 | if (i->index != 0) |
1509 | return -EINVAL; | 1504 | return -EINVAL; |
1510 | strcpy(i->name,"Radio"); | 1505 | strcpy(i->name,"Radio"); |
1511 | i->type = V4L2_INPUT_TYPE_TUNER; | 1506 | i->type = V4L2_INPUT_TYPE_TUNER; |
1512 | 1507 | ||
1513 | return 0; | 1508 | return 0; |
1514 | } | 1509 | } |
1515 | 1510 | ||
1516 | static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) | 1511 | static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) |
1517 | { | 1512 | { |
1518 | if (unlikely(a->index)) | 1513 | if (unlikely(a->index)) |
1519 | return -EINVAL; | 1514 | return -EINVAL; |
1520 | 1515 | ||
1521 | strcpy(a->name,"Radio"); | 1516 | strcpy(a->name,"Radio"); |
1522 | return 0; | 1517 | return 0; |
1523 | } | 1518 | } |
1524 | 1519 | ||
1525 | /* FIXME: Should add a standard for radio */ | 1520 | /* FIXME: Should add a standard for radio */ |
1526 | 1521 | ||
1527 | static int radio_s_tuner (struct file *file, void *priv, | 1522 | static int radio_s_tuner (struct file *file, void *priv, |
1528 | struct v4l2_tuner *t) | 1523 | struct v4l2_tuner *t) |
1529 | { | 1524 | { |
1530 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | 1525 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1531 | 1526 | ||
1532 | if (0 != t->index) | 1527 | if (0 != t->index) |
1533 | return -EINVAL; | 1528 | return -EINVAL; |
1534 | 1529 | ||
1535 | cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); | 1530 | cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); |
1536 | 1531 | ||
1537 | return 0; | 1532 | return 0; |
1538 | } | 1533 | } |
1539 | 1534 | ||
1540 | static int radio_s_audio (struct file *file, void *fh, | 1535 | static int radio_s_audio (struct file *file, void *fh, |
1541 | struct v4l2_audio *a) | 1536 | struct v4l2_audio *a) |
1542 | { | 1537 | { |
1543 | return 0; | 1538 | return 0; |
1544 | } | 1539 | } |
1545 | 1540 | ||
1546 | static int radio_s_input (struct file *file, void *fh, unsigned int i) | 1541 | static int radio_s_input (struct file *file, void *fh, unsigned int i) |
1547 | { | 1542 | { |
1548 | return 0; | 1543 | return 0; |
1549 | } | 1544 | } |
1550 | 1545 | ||
1551 | static int radio_queryctrl (struct file *file, void *priv, | 1546 | static int radio_queryctrl (struct file *file, void *priv, |
1552 | struct v4l2_queryctrl *c) | 1547 | struct v4l2_queryctrl *c) |
1553 | { | 1548 | { |
1554 | int i; | 1549 | int i; |
1555 | 1550 | ||
1556 | if (c->id < V4L2_CID_BASE || | 1551 | if (c->id < V4L2_CID_BASE || |
1557 | c->id >= V4L2_CID_LASTP1) | 1552 | c->id >= V4L2_CID_LASTP1) |
1558 | return -EINVAL; | 1553 | return -EINVAL; |
1559 | if (c->id == V4L2_CID_AUDIO_MUTE) { | 1554 | if (c->id == V4L2_CID_AUDIO_MUTE) { |
1560 | for (i = 0; i < CX8800_CTLS; i++) | 1555 | for (i = 0; i < CX8800_CTLS; i++) |
1561 | if (cx8800_ctls[i].v.id == c->id) | 1556 | if (cx8800_ctls[i].v.id == c->id) |
1562 | break; | 1557 | break; |
1563 | *c = cx8800_ctls[i].v; | 1558 | *c = cx8800_ctls[i].v; |
1564 | } else | 1559 | } else |
1565 | *c = no_ctl; | 1560 | *c = no_ctl; |
1566 | return 0; | 1561 | return 0; |
1567 | } | 1562 | } |
1568 | 1563 | ||
1569 | /* ----------------------------------------------------------- */ | 1564 | /* ----------------------------------------------------------- */ |
1570 | 1565 | ||
1571 | static void cx8800_vid_timeout(unsigned long data) | 1566 | static void cx8800_vid_timeout(unsigned long data) |
1572 | { | 1567 | { |
1573 | struct cx8800_dev *dev = (struct cx8800_dev*)data; | 1568 | struct cx8800_dev *dev = (struct cx8800_dev*)data; |
1574 | struct cx88_core *core = dev->core; | 1569 | struct cx88_core *core = dev->core; |
1575 | struct cx88_dmaqueue *q = &dev->vidq; | 1570 | struct cx88_dmaqueue *q = &dev->vidq; |
1576 | struct cx88_buffer *buf; | 1571 | struct cx88_buffer *buf; |
1577 | unsigned long flags; | 1572 | unsigned long flags; |
1578 | 1573 | ||
1579 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); | 1574 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); |
1580 | 1575 | ||
1581 | cx_clear(MO_VID_DMACNTRL, 0x11); | 1576 | cx_clear(MO_VID_DMACNTRL, 0x11); |
1582 | cx_clear(VID_CAPTURE_CONTROL, 0x06); | 1577 | cx_clear(VID_CAPTURE_CONTROL, 0x06); |
1583 | 1578 | ||
1584 | spin_lock_irqsave(&dev->slock,flags); | 1579 | spin_lock_irqsave(&dev->slock,flags); |
1585 | while (!list_empty(&q->active)) { | 1580 | while (!list_empty(&q->active)) { |
1586 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); | 1581 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); |
1587 | list_del(&buf->vb.queue); | 1582 | list_del(&buf->vb.queue); |
1588 | buf->vb.state = VIDEOBUF_ERROR; | 1583 | buf->vb.state = VIDEOBUF_ERROR; |
1589 | wake_up(&buf->vb.done); | 1584 | wake_up(&buf->vb.done); |
1590 | printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, | 1585 | printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, |
1591 | buf, buf->vb.i, (unsigned long)buf->risc.dma); | 1586 | buf, buf->vb.i, (unsigned long)buf->risc.dma); |
1592 | } | 1587 | } |
1593 | restart_video_queue(dev,q); | 1588 | restart_video_queue(dev,q); |
1594 | spin_unlock_irqrestore(&dev->slock,flags); | 1589 | spin_unlock_irqrestore(&dev->slock,flags); |
1595 | } | 1590 | } |
1596 | 1591 | ||
1597 | static char *cx88_vid_irqs[32] = { | 1592 | static char *cx88_vid_irqs[32] = { |
1598 | "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", | 1593 | "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", |
1599 | "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", | 1594 | "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", |
1600 | "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", | 1595 | "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", |
1601 | "y_sync", "u_sync", "v_sync", "vbi_sync", | 1596 | "y_sync", "u_sync", "v_sync", "vbi_sync", |
1602 | "opc_err", "par_err", "rip_err", "pci_abort", | 1597 | "opc_err", "par_err", "rip_err", "pci_abort", |
1603 | }; | 1598 | }; |
1604 | 1599 | ||
1605 | static void cx8800_vid_irq(struct cx8800_dev *dev) | 1600 | static void cx8800_vid_irq(struct cx8800_dev *dev) |
1606 | { | 1601 | { |
1607 | struct cx88_core *core = dev->core; | 1602 | struct cx88_core *core = dev->core; |
1608 | u32 status, mask, count; | 1603 | u32 status, mask, count; |
1609 | 1604 | ||
1610 | status = cx_read(MO_VID_INTSTAT); | 1605 | status = cx_read(MO_VID_INTSTAT); |
1611 | mask = cx_read(MO_VID_INTMSK); | 1606 | mask = cx_read(MO_VID_INTMSK); |
1612 | if (0 == (status & mask)) | 1607 | if (0 == (status & mask)) |
1613 | return; | 1608 | return; |
1614 | cx_write(MO_VID_INTSTAT, status); | 1609 | cx_write(MO_VID_INTSTAT, status); |
1615 | if (irq_debug || (status & mask & ~0xff)) | 1610 | if (irq_debug || (status & mask & ~0xff)) |
1616 | cx88_print_irqbits(core->name, "irq vid", | 1611 | cx88_print_irqbits(core->name, "irq vid", |
1617 | cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), | 1612 | cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), |
1618 | status, mask); | 1613 | status, mask); |
1619 | 1614 | ||
1620 | /* risc op code error */ | 1615 | /* risc op code error */ |
1621 | if (status & (1 << 16)) { | 1616 | if (status & (1 << 16)) { |
1622 | printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); | 1617 | printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); |
1623 | cx_clear(MO_VID_DMACNTRL, 0x11); | 1618 | cx_clear(MO_VID_DMACNTRL, 0x11); |
1624 | cx_clear(VID_CAPTURE_CONTROL, 0x06); | 1619 | cx_clear(VID_CAPTURE_CONTROL, 0x06); |
1625 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); | 1620 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); |
1626 | } | 1621 | } |
1627 | 1622 | ||
1628 | /* risc1 y */ | 1623 | /* risc1 y */ |
1629 | if (status & 0x01) { | 1624 | if (status & 0x01) { |
1630 | spin_lock(&dev->slock); | 1625 | spin_lock(&dev->slock); |
1631 | count = cx_read(MO_VIDY_GPCNT); | 1626 | count = cx_read(MO_VIDY_GPCNT); |
1632 | cx88_wakeup(core, &dev->vidq, count); | 1627 | cx88_wakeup(core, &dev->vidq, count); |
1633 | spin_unlock(&dev->slock); | 1628 | spin_unlock(&dev->slock); |
1634 | } | 1629 | } |
1635 | 1630 | ||
1636 | /* risc1 vbi */ | 1631 | /* risc1 vbi */ |
1637 | if (status & 0x08) { | 1632 | if (status & 0x08) { |
1638 | spin_lock(&dev->slock); | 1633 | spin_lock(&dev->slock); |
1639 | count = cx_read(MO_VBI_GPCNT); | 1634 | count = cx_read(MO_VBI_GPCNT); |
1640 | cx88_wakeup(core, &dev->vbiq, count); | 1635 | cx88_wakeup(core, &dev->vbiq, count); |
1641 | spin_unlock(&dev->slock); | 1636 | spin_unlock(&dev->slock); |
1642 | } | 1637 | } |
1643 | 1638 | ||
1644 | /* risc2 y */ | 1639 | /* risc2 y */ |
1645 | if (status & 0x10) { | 1640 | if (status & 0x10) { |
1646 | dprintk(2,"stopper video\n"); | 1641 | dprintk(2,"stopper video\n"); |
1647 | spin_lock(&dev->slock); | 1642 | spin_lock(&dev->slock); |
1648 | restart_video_queue(dev,&dev->vidq); | 1643 | restart_video_queue(dev,&dev->vidq); |
1649 | spin_unlock(&dev->slock); | 1644 | spin_unlock(&dev->slock); |
1650 | } | 1645 | } |
1651 | 1646 | ||
1652 | /* risc2 vbi */ | 1647 | /* risc2 vbi */ |
1653 | if (status & 0x80) { | 1648 | if (status & 0x80) { |
1654 | dprintk(2,"stopper vbi\n"); | 1649 | dprintk(2,"stopper vbi\n"); |
1655 | spin_lock(&dev->slock); | 1650 | spin_lock(&dev->slock); |
1656 | cx8800_restart_vbi_queue(dev,&dev->vbiq); | 1651 | cx8800_restart_vbi_queue(dev,&dev->vbiq); |
1657 | spin_unlock(&dev->slock); | 1652 | spin_unlock(&dev->slock); |
1658 | } | 1653 | } |
1659 | } | 1654 | } |
1660 | 1655 | ||
1661 | static irqreturn_t cx8800_irq(int irq, void *dev_id) | 1656 | static irqreturn_t cx8800_irq(int irq, void *dev_id) |
1662 | { | 1657 | { |
1663 | struct cx8800_dev *dev = dev_id; | 1658 | struct cx8800_dev *dev = dev_id; |
1664 | struct cx88_core *core = dev->core; | 1659 | struct cx88_core *core = dev->core; |
1665 | u32 status; | 1660 | u32 status; |
1666 | int loop, handled = 0; | 1661 | int loop, handled = 0; |
1667 | 1662 | ||
1668 | for (loop = 0; loop < 10; loop++) { | 1663 | for (loop = 0; loop < 10; loop++) { |
1669 | status = cx_read(MO_PCI_INTSTAT) & | 1664 | status = cx_read(MO_PCI_INTSTAT) & |
1670 | (core->pci_irqmask | PCI_INT_VIDINT); | 1665 | (core->pci_irqmask | PCI_INT_VIDINT); |
1671 | if (0 == status) | 1666 | if (0 == status) |
1672 | goto out; | 1667 | goto out; |
1673 | cx_write(MO_PCI_INTSTAT, status); | 1668 | cx_write(MO_PCI_INTSTAT, status); |
1674 | handled = 1; | 1669 | handled = 1; |
1675 | 1670 | ||
1676 | if (status & core->pci_irqmask) | 1671 | if (status & core->pci_irqmask) |
1677 | cx88_core_irq(core,status); | 1672 | cx88_core_irq(core,status); |
1678 | if (status & PCI_INT_VIDINT) | 1673 | if (status & PCI_INT_VIDINT) |
1679 | cx8800_vid_irq(dev); | 1674 | cx8800_vid_irq(dev); |
1680 | }; | 1675 | }; |
1681 | if (10 == loop) { | 1676 | if (10 == loop) { |
1682 | printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", | 1677 | printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", |
1683 | core->name); | 1678 | core->name); |
1684 | cx_write(MO_PCI_INTMSK,0); | 1679 | cx_write(MO_PCI_INTMSK,0); |
1685 | } | 1680 | } |
1686 | 1681 | ||
1687 | out: | 1682 | out: |
1688 | return IRQ_RETVAL(handled); | 1683 | return IRQ_RETVAL(handled); |
1689 | } | 1684 | } |
1690 | 1685 | ||
1691 | /* ----------------------------------------------------------- */ | 1686 | /* ----------------------------------------------------------- */ |
1692 | /* exported stuff */ | 1687 | /* exported stuff */ |
1693 | 1688 | ||
1694 | static const struct v4l2_file_operations video_fops = | 1689 | static const struct v4l2_file_operations video_fops = |
1695 | { | 1690 | { |
1696 | .owner = THIS_MODULE, | 1691 | .owner = THIS_MODULE, |
1697 | .open = video_open, | 1692 | .open = video_open, |
1698 | .release = video_release, | 1693 | .release = video_release, |
1699 | .read = video_read, | 1694 | .read = video_read, |
1700 | .poll = video_poll, | 1695 | .poll = video_poll, |
1701 | .mmap = video_mmap, | 1696 | .mmap = video_mmap, |
1702 | .ioctl = video_ioctl2, | 1697 | .ioctl = video_ioctl2, |
1703 | }; | 1698 | }; |
1704 | 1699 | ||
1705 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | 1700 | static const struct v4l2_ioctl_ops video_ioctl_ops = { |
1706 | .vidioc_querycap = vidioc_querycap, | 1701 | .vidioc_querycap = vidioc_querycap, |
1707 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | 1702 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1708 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 1703 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
1709 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | 1704 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, |
1710 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | 1705 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, |
1711 | .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, | 1706 | .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, |
1712 | .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, | 1707 | .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, |
1713 | .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, | 1708 | .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, |
1714 | .vidioc_reqbufs = vidioc_reqbufs, | 1709 | .vidioc_reqbufs = vidioc_reqbufs, |
1715 | .vidioc_querybuf = vidioc_querybuf, | 1710 | .vidioc_querybuf = vidioc_querybuf, |
1716 | .vidioc_qbuf = vidioc_qbuf, | 1711 | .vidioc_qbuf = vidioc_qbuf, |
1717 | .vidioc_dqbuf = vidioc_dqbuf, | 1712 | .vidioc_dqbuf = vidioc_dqbuf, |
1718 | .vidioc_s_std = vidioc_s_std, | 1713 | .vidioc_s_std = vidioc_s_std, |
1719 | .vidioc_enum_input = vidioc_enum_input, | 1714 | .vidioc_enum_input = vidioc_enum_input, |
1720 | .vidioc_g_input = vidioc_g_input, | 1715 | .vidioc_g_input = vidioc_g_input, |
1721 | .vidioc_s_input = vidioc_s_input, | 1716 | .vidioc_s_input = vidioc_s_input, |
1722 | .vidioc_queryctrl = vidioc_queryctrl, | 1717 | .vidioc_queryctrl = vidioc_queryctrl, |
1723 | .vidioc_g_ctrl = vidioc_g_ctrl, | 1718 | .vidioc_g_ctrl = vidioc_g_ctrl, |
1724 | .vidioc_s_ctrl = vidioc_s_ctrl, | 1719 | .vidioc_s_ctrl = vidioc_s_ctrl, |
1725 | .vidioc_streamon = vidioc_streamon, | 1720 | .vidioc_streamon = vidioc_streamon, |
1726 | .vidioc_streamoff = vidioc_streamoff, | 1721 | .vidioc_streamoff = vidioc_streamoff, |
1727 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1722 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1728 | .vidiocgmbuf = vidiocgmbuf, | 1723 | .vidiocgmbuf = vidiocgmbuf, |
1729 | #endif | 1724 | #endif |
1730 | .vidioc_g_tuner = vidioc_g_tuner, | 1725 | .vidioc_g_tuner = vidioc_g_tuner, |
1731 | .vidioc_s_tuner = vidioc_s_tuner, | 1726 | .vidioc_s_tuner = vidioc_s_tuner, |
1732 | .vidioc_g_frequency = vidioc_g_frequency, | 1727 | .vidioc_g_frequency = vidioc_g_frequency, |
1733 | .vidioc_s_frequency = vidioc_s_frequency, | 1728 | .vidioc_s_frequency = vidioc_s_frequency, |
1734 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1729 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1735 | .vidioc_g_register = vidioc_g_register, | 1730 | .vidioc_g_register = vidioc_g_register, |
1736 | .vidioc_s_register = vidioc_s_register, | 1731 | .vidioc_s_register = vidioc_s_register, |
1737 | #endif | 1732 | #endif |
1738 | }; | 1733 | }; |
1739 | 1734 | ||
1740 | static struct video_device cx8800_vbi_template; | 1735 | static struct video_device cx8800_vbi_template; |
1741 | 1736 | ||
1742 | static struct video_device cx8800_video_template = { | 1737 | static struct video_device cx8800_video_template = { |
1743 | .name = "cx8800-video", | 1738 | .name = "cx8800-video", |
1744 | .fops = &video_fops, | 1739 | .fops = &video_fops, |
1745 | .minor = -1, | 1740 | .minor = -1, |
1746 | .ioctl_ops = &video_ioctl_ops, | 1741 | .ioctl_ops = &video_ioctl_ops, |
1747 | .tvnorms = CX88_NORMS, | 1742 | .tvnorms = CX88_NORMS, |
1748 | .current_norm = V4L2_STD_NTSC_M, | 1743 | .current_norm = V4L2_STD_NTSC_M, |
1749 | }; | 1744 | }; |
1750 | 1745 | ||
1751 | static const struct v4l2_file_operations radio_fops = | 1746 | static const struct v4l2_file_operations radio_fops = |
1752 | { | 1747 | { |
1753 | .owner = THIS_MODULE, | 1748 | .owner = THIS_MODULE, |
1754 | .open = video_open, | 1749 | .open = video_open, |
1755 | .release = video_release, | 1750 | .release = video_release, |
1756 | .ioctl = video_ioctl2, | 1751 | .ioctl = video_ioctl2, |
1757 | }; | 1752 | }; |
1758 | 1753 | ||
1759 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { | 1754 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { |
1760 | .vidioc_querycap = radio_querycap, | 1755 | .vidioc_querycap = radio_querycap, |
1761 | .vidioc_g_tuner = radio_g_tuner, | 1756 | .vidioc_g_tuner = radio_g_tuner, |
1762 | .vidioc_enum_input = radio_enum_input, | 1757 | .vidioc_enum_input = radio_enum_input, |
1763 | .vidioc_g_audio = radio_g_audio, | 1758 | .vidioc_g_audio = radio_g_audio, |
1764 | .vidioc_s_tuner = radio_s_tuner, | 1759 | .vidioc_s_tuner = radio_s_tuner, |
1765 | .vidioc_s_audio = radio_s_audio, | 1760 | .vidioc_s_audio = radio_s_audio, |
1766 | .vidioc_s_input = radio_s_input, | 1761 | .vidioc_s_input = radio_s_input, |
1767 | .vidioc_queryctrl = radio_queryctrl, | 1762 | .vidioc_queryctrl = radio_queryctrl, |
1768 | .vidioc_g_ctrl = vidioc_g_ctrl, | 1763 | .vidioc_g_ctrl = vidioc_g_ctrl, |
1769 | .vidioc_s_ctrl = vidioc_s_ctrl, | 1764 | .vidioc_s_ctrl = vidioc_s_ctrl, |
1770 | .vidioc_g_frequency = vidioc_g_frequency, | 1765 | .vidioc_g_frequency = vidioc_g_frequency, |
1771 | .vidioc_s_frequency = vidioc_s_frequency, | 1766 | .vidioc_s_frequency = vidioc_s_frequency, |
1772 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1767 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1773 | .vidioc_g_register = vidioc_g_register, | 1768 | .vidioc_g_register = vidioc_g_register, |
1774 | .vidioc_s_register = vidioc_s_register, | 1769 | .vidioc_s_register = vidioc_s_register, |
1775 | #endif | 1770 | #endif |
1776 | }; | 1771 | }; |
1777 | 1772 | ||
1778 | static struct video_device cx8800_radio_template = { | 1773 | static struct video_device cx8800_radio_template = { |
1779 | .name = "cx8800-radio", | 1774 | .name = "cx8800-radio", |
1780 | .fops = &radio_fops, | 1775 | .fops = &radio_fops, |
1781 | .minor = -1, | 1776 | .minor = -1, |
1782 | .ioctl_ops = &radio_ioctl_ops, | 1777 | .ioctl_ops = &radio_ioctl_ops, |
1783 | }; | 1778 | }; |
1784 | 1779 | ||
1785 | /* ----------------------------------------------------------- */ | 1780 | /* ----------------------------------------------------------- */ |
1786 | 1781 | ||
1787 | static void cx8800_unregister_video(struct cx8800_dev *dev) | 1782 | static void cx8800_unregister_video(struct cx8800_dev *dev) |
1788 | { | 1783 | { |
1789 | if (dev->radio_dev) { | 1784 | if (dev->radio_dev) { |
1790 | if (-1 != dev->radio_dev->minor) | 1785 | if (-1 != dev->radio_dev->minor) |
1791 | video_unregister_device(dev->radio_dev); | 1786 | video_unregister_device(dev->radio_dev); |
1792 | else | 1787 | else |
1793 | video_device_release(dev->radio_dev); | 1788 | video_device_release(dev->radio_dev); |
1794 | dev->radio_dev = NULL; | 1789 | dev->radio_dev = NULL; |
1795 | } | 1790 | } |
1796 | if (dev->vbi_dev) { | 1791 | if (dev->vbi_dev) { |
1797 | if (-1 != dev->vbi_dev->minor) | 1792 | if (-1 != dev->vbi_dev->minor) |
1798 | video_unregister_device(dev->vbi_dev); | 1793 | video_unregister_device(dev->vbi_dev); |
1799 | else | 1794 | else |
1800 | video_device_release(dev->vbi_dev); | 1795 | video_device_release(dev->vbi_dev); |
1801 | dev->vbi_dev = NULL; | 1796 | dev->vbi_dev = NULL; |
1802 | } | 1797 | } |
1803 | if (dev->video_dev) { | 1798 | if (dev->video_dev) { |
1804 | if (-1 != dev->video_dev->minor) | 1799 | if (-1 != dev->video_dev->minor) |
1805 | video_unregister_device(dev->video_dev); | 1800 | video_unregister_device(dev->video_dev); |
1806 | else | 1801 | else |
1807 | video_device_release(dev->video_dev); | 1802 | video_device_release(dev->video_dev); |
1808 | dev->video_dev = NULL; | 1803 | dev->video_dev = NULL; |
1809 | } | 1804 | } |
1810 | } | 1805 | } |
1811 | 1806 | ||
1812 | static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | 1807 | static int __devinit cx8800_initdev(struct pci_dev *pci_dev, |
1813 | const struct pci_device_id *pci_id) | 1808 | const struct pci_device_id *pci_id) |
1814 | { | 1809 | { |
1815 | struct cx8800_dev *dev; | 1810 | struct cx8800_dev *dev; |
1816 | struct cx88_core *core; | 1811 | struct cx88_core *core; |
1817 | 1812 | ||
1818 | int err; | 1813 | int err; |
1819 | 1814 | ||
1820 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | 1815 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); |
1821 | if (NULL == dev) | 1816 | if (NULL == dev) |
1822 | return -ENOMEM; | 1817 | return -ENOMEM; |
1823 | 1818 | ||
1824 | /* pci init */ | 1819 | /* pci init */ |
1825 | dev->pci = pci_dev; | 1820 | dev->pci = pci_dev; |
1826 | if (pci_enable_device(pci_dev)) { | 1821 | if (pci_enable_device(pci_dev)) { |
1827 | err = -EIO; | 1822 | err = -EIO; |
1828 | goto fail_free; | 1823 | goto fail_free; |
1829 | } | 1824 | } |
1830 | core = cx88_core_get(dev->pci); | 1825 | core = cx88_core_get(dev->pci); |
1831 | if (NULL == core) { | 1826 | if (NULL == core) { |
1832 | err = -EINVAL; | 1827 | err = -EINVAL; |
1833 | goto fail_free; | 1828 | goto fail_free; |
1834 | } | 1829 | } |
1835 | dev->core = core; | 1830 | dev->core = core; |
1836 | 1831 | ||
1837 | /* print pci info */ | 1832 | /* print pci info */ |
1838 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 1833 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); |
1839 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | 1834 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
1840 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | 1835 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " |
1841 | "latency: %d, mmio: 0x%llx\n", core->name, | 1836 | "latency: %d, mmio: 0x%llx\n", core->name, |
1842 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | 1837 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, |
1843 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); | 1838 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); |
1844 | 1839 | ||
1845 | pci_set_master(pci_dev); | 1840 | pci_set_master(pci_dev); |
1846 | if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) { | 1841 | if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) { |
1847 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); | 1842 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); |
1848 | err = -EIO; | 1843 | err = -EIO; |
1849 | goto fail_core; | 1844 | goto fail_core; |
1850 | } | 1845 | } |
1851 | 1846 | ||
1852 | /* Initialize VBI template */ | 1847 | /* Initialize VBI template */ |
1853 | memcpy( &cx8800_vbi_template, &cx8800_video_template, | 1848 | memcpy( &cx8800_vbi_template, &cx8800_video_template, |
1854 | sizeof(cx8800_vbi_template) ); | 1849 | sizeof(cx8800_vbi_template) ); |
1855 | strcpy(cx8800_vbi_template.name,"cx8800-vbi"); | 1850 | strcpy(cx8800_vbi_template.name,"cx8800-vbi"); |
1856 | 1851 | ||
1857 | /* initialize driver struct */ | 1852 | /* initialize driver struct */ |
1858 | spin_lock_init(&dev->slock); | 1853 | spin_lock_init(&dev->slock); |
1859 | core->tvnorm = cx8800_video_template.current_norm; | 1854 | core->tvnorm = cx8800_video_template.current_norm; |
1860 | 1855 | ||
1861 | /* init video dma queues */ | 1856 | /* init video dma queues */ |
1862 | INIT_LIST_HEAD(&dev->vidq.active); | 1857 | INIT_LIST_HEAD(&dev->vidq.active); |
1863 | INIT_LIST_HEAD(&dev->vidq.queued); | 1858 | INIT_LIST_HEAD(&dev->vidq.queued); |
1864 | dev->vidq.timeout.function = cx8800_vid_timeout; | 1859 | dev->vidq.timeout.function = cx8800_vid_timeout; |
1865 | dev->vidq.timeout.data = (unsigned long)dev; | 1860 | dev->vidq.timeout.data = (unsigned long)dev; |
1866 | init_timer(&dev->vidq.timeout); | 1861 | init_timer(&dev->vidq.timeout); |
1867 | cx88_risc_stopper(dev->pci,&dev->vidq.stopper, | 1862 | cx88_risc_stopper(dev->pci,&dev->vidq.stopper, |
1868 | MO_VID_DMACNTRL,0x11,0x00); | 1863 | MO_VID_DMACNTRL,0x11,0x00); |
1869 | 1864 | ||
1870 | /* init vbi dma queues */ | 1865 | /* init vbi dma queues */ |
1871 | INIT_LIST_HEAD(&dev->vbiq.active); | 1866 | INIT_LIST_HEAD(&dev->vbiq.active); |
1872 | INIT_LIST_HEAD(&dev->vbiq.queued); | 1867 | INIT_LIST_HEAD(&dev->vbiq.queued); |
1873 | dev->vbiq.timeout.function = cx8800_vbi_timeout; | 1868 | dev->vbiq.timeout.function = cx8800_vbi_timeout; |
1874 | dev->vbiq.timeout.data = (unsigned long)dev; | 1869 | dev->vbiq.timeout.data = (unsigned long)dev; |
1875 | init_timer(&dev->vbiq.timeout); | 1870 | init_timer(&dev->vbiq.timeout); |
1876 | cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, | 1871 | cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, |
1877 | MO_VID_DMACNTRL,0x88,0x00); | 1872 | MO_VID_DMACNTRL,0x88,0x00); |
1878 | 1873 | ||
1879 | /* get irq */ | 1874 | /* get irq */ |
1880 | err = request_irq(pci_dev->irq, cx8800_irq, | 1875 | err = request_irq(pci_dev->irq, cx8800_irq, |
1881 | IRQF_SHARED | IRQF_DISABLED, core->name, dev); | 1876 | IRQF_SHARED | IRQF_DISABLED, core->name, dev); |
1882 | if (err < 0) { | 1877 | if (err < 0) { |
1883 | printk(KERN_ERR "%s/0: can't get IRQ %d\n", | 1878 | printk(KERN_ERR "%s/0: can't get IRQ %d\n", |
1884 | core->name,pci_dev->irq); | 1879 | core->name,pci_dev->irq); |
1885 | goto fail_core; | 1880 | goto fail_core; |
1886 | } | 1881 | } |
1887 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | 1882 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); |
1888 | 1883 | ||
1889 | /* load and configure helper modules */ | 1884 | /* load and configure helper modules */ |
1890 | 1885 | ||
1891 | if (core->board.audio_chip == V4L2_IDENT_WM8775) | 1886 | if (core->board.audio_chip == V4L2_IDENT_WM8775) |
1892 | request_module("wm8775"); | 1887 | request_module("wm8775"); |
1893 | 1888 | ||
1894 | switch (core->boardnr) { | 1889 | switch (core->boardnr) { |
1895 | case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: | 1890 | case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: |
1896 | case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: | 1891 | case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: |
1897 | request_module("rtc-isl1208"); | 1892 | request_module("rtc-isl1208"); |
1898 | /* break intentionally omitted */ | 1893 | /* break intentionally omitted */ |
1899 | case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: | 1894 | case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: |
1900 | request_module("ir-kbd-i2c"); | 1895 | request_module("ir-kbd-i2c"); |
1901 | } | 1896 | } |
1902 | 1897 | ||
1903 | /* register v4l devices */ | 1898 | /* register v4l devices */ |
1904 | dev->video_dev = cx88_vdev_init(core,dev->pci, | 1899 | dev->video_dev = cx88_vdev_init(core,dev->pci, |
1905 | &cx8800_video_template,"video"); | 1900 | &cx8800_video_template,"video"); |
1906 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | 1901 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, |
1907 | video_nr[core->nr]); | 1902 | video_nr[core->nr]); |
1908 | if (err < 0) { | 1903 | if (err < 0) { |
1909 | printk(KERN_ERR "%s/0: can't register video device\n", | 1904 | printk(KERN_ERR "%s/0: can't register video device\n", |
1910 | core->name); | 1905 | core->name); |
1911 | goto fail_unreg; | 1906 | goto fail_unreg; |
1912 | } | 1907 | } |
1913 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", | 1908 | printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", |
1914 | core->name, dev->video_dev->num); | 1909 | core->name, dev->video_dev->num); |
1915 | 1910 | ||
1916 | dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); | 1911 | dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); |
1917 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | 1912 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, |
1918 | vbi_nr[core->nr]); | 1913 | vbi_nr[core->nr]); |
1919 | if (err < 0) { | 1914 | if (err < 0) { |
1920 | printk(KERN_ERR "%s/0: can't register vbi device\n", | 1915 | printk(KERN_ERR "%s/0: can't register vbi device\n", |
1921 | core->name); | 1916 | core->name); |
1922 | goto fail_unreg; | 1917 | goto fail_unreg; |
1923 | } | 1918 | } |
1924 | printk(KERN_INFO "%s/0: registered device vbi%d\n", | 1919 | printk(KERN_INFO "%s/0: registered device vbi%d\n", |
1925 | core->name, dev->vbi_dev->num); | 1920 | core->name, dev->vbi_dev->num); |
1926 | 1921 | ||
1927 | if (core->board.radio.type == CX88_RADIO) { | 1922 | if (core->board.radio.type == CX88_RADIO) { |
1928 | dev->radio_dev = cx88_vdev_init(core,dev->pci, | 1923 | dev->radio_dev = cx88_vdev_init(core,dev->pci, |
1929 | &cx8800_radio_template,"radio"); | 1924 | &cx8800_radio_template,"radio"); |
1930 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | 1925 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
1931 | radio_nr[core->nr]); | 1926 | radio_nr[core->nr]); |
1932 | if (err < 0) { | 1927 | if (err < 0) { |
1933 | printk(KERN_ERR "%s/0: can't register radio device\n", | 1928 | printk(KERN_ERR "%s/0: can't register radio device\n", |
1934 | core->name); | 1929 | core->name); |
1935 | goto fail_unreg; | 1930 | goto fail_unreg; |
1936 | } | 1931 | } |
1937 | printk(KERN_INFO "%s/0: registered device radio%d\n", | 1932 | printk(KERN_INFO "%s/0: registered device radio%d\n", |
1938 | core->name, dev->radio_dev->num); | 1933 | core->name, dev->radio_dev->num); |
1939 | } | 1934 | } |
1940 | 1935 | ||
1941 | /* everything worked */ | 1936 | /* everything worked */ |
1942 | list_add_tail(&dev->devlist,&cx8800_devlist); | 1937 | list_add_tail(&dev->devlist,&cx8800_devlist); |
1943 | pci_set_drvdata(pci_dev,dev); | 1938 | pci_set_drvdata(pci_dev,dev); |
1944 | 1939 | ||
1945 | /* initial device configuration */ | 1940 | /* initial device configuration */ |
1946 | mutex_lock(&core->lock); | 1941 | mutex_lock(&core->lock); |
1947 | cx88_set_tvnorm(core,core->tvnorm); | 1942 | cx88_set_tvnorm(core,core->tvnorm); |
1948 | init_controls(core); | 1943 | init_controls(core); |
1949 | cx88_video_mux(core,0); | 1944 | cx88_video_mux(core,0); |
1950 | mutex_unlock(&core->lock); | 1945 | mutex_unlock(&core->lock); |
1951 | 1946 | ||
1952 | /* start tvaudio thread */ | 1947 | /* start tvaudio thread */ |
1953 | if (core->board.tuner_type != TUNER_ABSENT) { | 1948 | if (core->board.tuner_type != TUNER_ABSENT) { |
1954 | core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); | 1949 | core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); |
1955 | if (IS_ERR(core->kthread)) { | 1950 | if (IS_ERR(core->kthread)) { |
1956 | err = PTR_ERR(core->kthread); | 1951 | err = PTR_ERR(core->kthread); |
1957 | printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", | 1952 | printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", |
1958 | core->name, err); | 1953 | core->name, err); |
1959 | } | 1954 | } |
1960 | } | 1955 | } |
1961 | return 0; | 1956 | return 0; |
1962 | 1957 | ||
1963 | fail_unreg: | 1958 | fail_unreg: |
1964 | cx8800_unregister_video(dev); | 1959 | cx8800_unregister_video(dev); |
1965 | free_irq(pci_dev->irq, dev); | 1960 | free_irq(pci_dev->irq, dev); |
1966 | fail_core: | 1961 | fail_core: |
1967 | cx88_core_put(core,dev->pci); | 1962 | cx88_core_put(core,dev->pci); |
1968 | fail_free: | 1963 | fail_free: |
1969 | kfree(dev); | 1964 | kfree(dev); |
1970 | return err; | 1965 | return err; |
1971 | } | 1966 | } |
1972 | 1967 | ||
1973 | static void __devexit cx8800_finidev(struct pci_dev *pci_dev) | 1968 | static void __devexit cx8800_finidev(struct pci_dev *pci_dev) |
1974 | { | 1969 | { |
1975 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 1970 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); |
1976 | struct cx88_core *core = dev->core; | 1971 | struct cx88_core *core = dev->core; |
1977 | 1972 | ||
1978 | /* stop thread */ | 1973 | /* stop thread */ |
1979 | if (core->kthread) { | 1974 | if (core->kthread) { |
1980 | kthread_stop(core->kthread); | 1975 | kthread_stop(core->kthread); |
1981 | core->kthread = NULL; | 1976 | core->kthread = NULL; |
1982 | } | 1977 | } |
1983 | 1978 | ||
1984 | if (core->ir) | 1979 | if (core->ir) |
1985 | cx88_ir_stop(core, core->ir); | 1980 | cx88_ir_stop(core, core->ir); |
1986 | 1981 | ||
1987 | cx88_shutdown(core); /* FIXME */ | 1982 | cx88_shutdown(core); /* FIXME */ |
1988 | pci_disable_device(pci_dev); | 1983 | pci_disable_device(pci_dev); |
1989 | 1984 | ||
1990 | /* unregister stuff */ | 1985 | /* unregister stuff */ |
1991 | 1986 | ||
1992 | free_irq(pci_dev->irq, dev); | 1987 | free_irq(pci_dev->irq, dev); |
1993 | cx8800_unregister_video(dev); | 1988 | cx8800_unregister_video(dev); |
1994 | pci_set_drvdata(pci_dev, NULL); | 1989 | pci_set_drvdata(pci_dev, NULL); |
1995 | 1990 | ||
1996 | /* free memory */ | 1991 | /* free memory */ |
1997 | btcx_riscmem_free(dev->pci,&dev->vidq.stopper); | 1992 | btcx_riscmem_free(dev->pci,&dev->vidq.stopper); |
1998 | list_del(&dev->devlist); | 1993 | list_del(&dev->devlist); |
1999 | cx88_core_put(core,dev->pci); | 1994 | cx88_core_put(core,dev->pci); |
2000 | kfree(dev); | 1995 | kfree(dev); |
2001 | } | 1996 | } |
2002 | 1997 | ||
2003 | #ifdef CONFIG_PM | 1998 | #ifdef CONFIG_PM |
2004 | static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | 1999 | static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) |
2005 | { | 2000 | { |
2006 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 2001 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); |
2007 | struct cx88_core *core = dev->core; | 2002 | struct cx88_core *core = dev->core; |
2008 | 2003 | ||
2009 | /* stop video+vbi capture */ | 2004 | /* stop video+vbi capture */ |
2010 | spin_lock(&dev->slock); | 2005 | spin_lock(&dev->slock); |
2011 | if (!list_empty(&dev->vidq.active)) { | 2006 | if (!list_empty(&dev->vidq.active)) { |
2012 | printk("%s/0: suspend video\n", core->name); | 2007 | printk("%s/0: suspend video\n", core->name); |
2013 | stop_video_dma(dev); | 2008 | stop_video_dma(dev); |
2014 | del_timer(&dev->vidq.timeout); | 2009 | del_timer(&dev->vidq.timeout); |
2015 | } | 2010 | } |
2016 | if (!list_empty(&dev->vbiq.active)) { | 2011 | if (!list_empty(&dev->vbiq.active)) { |
2017 | printk("%s/0: suspend vbi\n", core->name); | 2012 | printk("%s/0: suspend vbi\n", core->name); |
2018 | cx8800_stop_vbi_dma(dev); | 2013 | cx8800_stop_vbi_dma(dev); |
2019 | del_timer(&dev->vbiq.timeout); | 2014 | del_timer(&dev->vbiq.timeout); |
2020 | } | 2015 | } |
2021 | spin_unlock(&dev->slock); | 2016 | spin_unlock(&dev->slock); |
2022 | 2017 | ||
2023 | if (core->ir) | 2018 | if (core->ir) |
2024 | cx88_ir_stop(core, core->ir); | 2019 | cx88_ir_stop(core, core->ir); |
2025 | /* FIXME -- shutdown device */ | 2020 | /* FIXME -- shutdown device */ |
2026 | cx88_shutdown(core); | 2021 | cx88_shutdown(core); |
2027 | 2022 | ||
2028 | pci_save_state(pci_dev); | 2023 | pci_save_state(pci_dev); |
2029 | if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { | 2024 | if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { |
2030 | pci_disable_device(pci_dev); | 2025 | pci_disable_device(pci_dev); |
2031 | dev->state.disabled = 1; | 2026 | dev->state.disabled = 1; |
2032 | } | 2027 | } |
2033 | return 0; | 2028 | return 0; |
2034 | } | 2029 | } |
2035 | 2030 | ||
2036 | static int cx8800_resume(struct pci_dev *pci_dev) | 2031 | static int cx8800_resume(struct pci_dev *pci_dev) |
2037 | { | 2032 | { |
2038 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 2033 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); |
2039 | struct cx88_core *core = dev->core; | 2034 | struct cx88_core *core = dev->core; |
2040 | int err; | 2035 | int err; |
2041 | 2036 | ||
2042 | if (dev->state.disabled) { | 2037 | if (dev->state.disabled) { |
2043 | err=pci_enable_device(pci_dev); | 2038 | err=pci_enable_device(pci_dev); |
2044 | if (err) { | 2039 | if (err) { |
2045 | printk(KERN_ERR "%s/0: can't enable device\n", | 2040 | printk(KERN_ERR "%s/0: can't enable device\n", |
2046 | core->name); | 2041 | core->name); |
2047 | return err; | 2042 | return err; |
2048 | } | 2043 | } |
2049 | 2044 | ||
2050 | dev->state.disabled = 0; | 2045 | dev->state.disabled = 0; |
2051 | } | 2046 | } |
2052 | err= pci_set_power_state(pci_dev, PCI_D0); | 2047 | err= pci_set_power_state(pci_dev, PCI_D0); |
2053 | if (err) { | 2048 | if (err) { |
2054 | printk(KERN_ERR "%s/0: can't set power state\n", core->name); | 2049 | printk(KERN_ERR "%s/0: can't set power state\n", core->name); |
2055 | pci_disable_device(pci_dev); | 2050 | pci_disable_device(pci_dev); |
2056 | dev->state.disabled = 1; | 2051 | dev->state.disabled = 1; |
2057 | 2052 | ||
2058 | return err; | 2053 | return err; |
2059 | } | 2054 | } |
2060 | pci_restore_state(pci_dev); | 2055 | pci_restore_state(pci_dev); |
2061 | 2056 | ||
2062 | /* FIXME: re-initialize hardware */ | 2057 | /* FIXME: re-initialize hardware */ |
2063 | cx88_reset(core); | 2058 | cx88_reset(core); |
2064 | if (core->ir) | 2059 | if (core->ir) |
2065 | cx88_ir_start(core, core->ir); | 2060 | cx88_ir_start(core, core->ir); |
2066 | 2061 | ||
2067 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | 2062 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); |
2068 | 2063 | ||
2069 | /* restart video+vbi capture */ | 2064 | /* restart video+vbi capture */ |
2070 | spin_lock(&dev->slock); | 2065 | spin_lock(&dev->slock); |
2071 | if (!list_empty(&dev->vidq.active)) { | 2066 | if (!list_empty(&dev->vidq.active)) { |
2072 | printk("%s/0: resume video\n", core->name); | 2067 | printk("%s/0: resume video\n", core->name); |
2073 | restart_video_queue(dev,&dev->vidq); | 2068 | restart_video_queue(dev,&dev->vidq); |
2074 | } | 2069 | } |
2075 | if (!list_empty(&dev->vbiq.active)) { | 2070 | if (!list_empty(&dev->vbiq.active)) { |
2076 | printk("%s/0: resume vbi\n", core->name); | 2071 | printk("%s/0: resume vbi\n", core->name); |
2077 | cx8800_restart_vbi_queue(dev,&dev->vbiq); | 2072 | cx8800_restart_vbi_queue(dev,&dev->vbiq); |
2078 | } | 2073 | } |
2079 | spin_unlock(&dev->slock); | 2074 | spin_unlock(&dev->slock); |
2080 | 2075 | ||
2081 | return 0; | 2076 | return 0; |
2082 | } | 2077 | } |
2083 | #endif | 2078 | #endif |
2084 | 2079 | ||
2085 | /* ----------------------------------------------------------- */ | 2080 | /* ----------------------------------------------------------- */ |
2086 | 2081 | ||
2087 | static struct pci_device_id cx8800_pci_tbl[] = { | 2082 | static struct pci_device_id cx8800_pci_tbl[] = { |
2088 | { | 2083 | { |
2089 | .vendor = 0x14f1, | 2084 | .vendor = 0x14f1, |
2090 | .device = 0x8800, | 2085 | .device = 0x8800, |
2091 | .subvendor = PCI_ANY_ID, | 2086 | .subvendor = PCI_ANY_ID, |
2092 | .subdevice = PCI_ANY_ID, | 2087 | .subdevice = PCI_ANY_ID, |
2093 | },{ | 2088 | },{ |
2094 | /* --- end of list --- */ | 2089 | /* --- end of list --- */ |
2095 | } | 2090 | } |
2096 | }; | 2091 | }; |
2097 | MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); | 2092 | MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); |
2098 | 2093 | ||
2099 | static struct pci_driver cx8800_pci_driver = { | 2094 | static struct pci_driver cx8800_pci_driver = { |
2100 | .name = "cx8800", | 2095 | .name = "cx8800", |
2101 | .id_table = cx8800_pci_tbl, | 2096 | .id_table = cx8800_pci_tbl, |
2102 | .probe = cx8800_initdev, | 2097 | .probe = cx8800_initdev, |
2103 | .remove = __devexit_p(cx8800_finidev), | 2098 | .remove = __devexit_p(cx8800_finidev), |
2104 | #ifdef CONFIG_PM | 2099 | #ifdef CONFIG_PM |
2105 | .suspend = cx8800_suspend, | 2100 | .suspend = cx8800_suspend, |
2106 | .resume = cx8800_resume, | 2101 | .resume = cx8800_resume, |
2107 | #endif | 2102 | #endif |
2108 | }; | 2103 | }; |
2109 | 2104 | ||
2110 | static int cx8800_init(void) | 2105 | static int cx8800_init(void) |
2111 | { | 2106 | { |
2112 | printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", | 2107 | printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", |
2113 | (CX88_VERSION_CODE >> 16) & 0xff, | 2108 | (CX88_VERSION_CODE >> 16) & 0xff, |
2114 | (CX88_VERSION_CODE >> 8) & 0xff, | 2109 | (CX88_VERSION_CODE >> 8) & 0xff, |
2115 | CX88_VERSION_CODE & 0xff); | 2110 | CX88_VERSION_CODE & 0xff); |
2116 | #ifdef SNAPSHOT | 2111 | #ifdef SNAPSHOT |
2117 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 2112 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
2118 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 2113 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
2119 | #endif | 2114 | #endif |
2120 | return pci_register_driver(&cx8800_pci_driver); | 2115 | return pci_register_driver(&cx8800_pci_driver); |
2121 | } | 2116 | } |
2122 | 2117 | ||
2123 | static void cx8800_fini(void) | 2118 | static void cx8800_fini(void) |
2124 | { | 2119 | { |
2125 | pci_unregister_driver(&cx8800_pci_driver); | 2120 | pci_unregister_driver(&cx8800_pci_driver); |
2126 | } | 2121 | } |
2127 | 2122 | ||
2128 | module_init(cx8800_init); | 2123 | module_init(cx8800_init); |
2129 | module_exit(cx8800_fini); | 2124 | module_exit(cx8800_fini); |
2130 | 2125 | ||
2131 | /* ----------------------------------------------------------- */ | 2126 | /* ----------------------------------------------------------- */ |
2132 | /* | 2127 | /* |
2133 | * Local variables: | 2128 | * Local variables: |
2134 | * c-basic-offset: 8 | 2129 | * c-basic-offset: 8 |
2135 | * End: | 2130 | * End: |
2136 | * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off | 2131 | * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off |
2137 | */ | 2132 | */ |
2138 | 2133 |
drivers/media/video/msp3400-driver.c
1 | /* | 1 | /* |
2 | * Programming the mspx4xx sound processor family | 2 | * Programming the mspx4xx sound processor family |
3 | * | 3 | * |
4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> | 4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> |
5 | * | 5 | * |
6 | * what works and what doesn't: | 6 | * what works and what doesn't: |
7 | * | 7 | * |
8 | * AM-Mono | 8 | * AM-Mono |
9 | * Support for Hauppauge cards added (decoding handled by tuner) added by | 9 | * Support for Hauppauge cards added (decoding handled by tuner) added by |
10 | * Frederic Crozat <fcrozat@mail.dotcom.fr> | 10 | * Frederic Crozat <fcrozat@mail.dotcom.fr> |
11 | * | 11 | * |
12 | * FM-Mono | 12 | * FM-Mono |
13 | * should work. The stereo modes are backward compatible to FM-mono, | 13 | * should work. The stereo modes are backward compatible to FM-mono, |
14 | * therefore FM-Mono should be allways available. | 14 | * therefore FM-Mono should be allways available. |
15 | * | 15 | * |
16 | * FM-Stereo (B/G, used in germany) | 16 | * FM-Stereo (B/G, used in germany) |
17 | * should work, with autodetect | 17 | * should work, with autodetect |
18 | * | 18 | * |
19 | * FM-Stereo (satellite) | 19 | * FM-Stereo (satellite) |
20 | * should work, no autodetect (i.e. default is mono, but you can | 20 | * should work, no autodetect (i.e. default is mono, but you can |
21 | * switch to stereo -- untested) | 21 | * switch to stereo -- untested) |
22 | * | 22 | * |
23 | * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) | 23 | * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) |
24 | * should work, with autodetect. Support for NICAM was added by | 24 | * should work, with autodetect. Support for NICAM was added by |
25 | * Pekka Pietikainen <pp@netppl.fi> | 25 | * Pekka Pietikainen <pp@netppl.fi> |
26 | * | 26 | * |
27 | * TODO: | 27 | * TODO: |
28 | * - better SAT support | 28 | * - better SAT support |
29 | * | 29 | * |
30 | * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) | 30 | * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) |
31 | * using soundcore instead of OSS | 31 | * using soundcore instead of OSS |
32 | * | 32 | * |
33 | * This program is free software; you can redistribute it and/or | 33 | * This program is free software; you can redistribute it and/or |
34 | * modify it under the terms of the GNU General Public License | 34 | * modify it under the terms of the GNU General Public License |
35 | * as published by the Free Software Foundation; either version 2 | 35 | * as published by the Free Software Foundation; either version 2 |
36 | * of the License, or (at your option) any later version. | 36 | * of the License, or (at your option) any later version. |
37 | * | 37 | * |
38 | * This program is distributed in the hope that it will be useful, | 38 | * This program is distributed in the hope that it will be useful, |
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
41 | * GNU General Public License for more details. | 41 | * GNU General Public License for more details. |
42 | * | 42 | * |
43 | * You should have received a copy of the GNU General Public License | 43 | * You should have received a copy of the GNU General Public License |
44 | * along with this program; if not, write to the Free Software | 44 | * along with this program; if not, write to the Free Software |
45 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 45 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
46 | * 02110-1301, USA. | 46 | * 02110-1301, USA. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <linux/kernel.h> | 50 | #include <linux/kernel.h> |
51 | #include <linux/module.h> | 51 | #include <linux/module.h> |
52 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
53 | #include <linux/i2c.h> | 53 | #include <linux/i2c.h> |
54 | #include <linux/kthread.h> | 54 | #include <linux/kthread.h> |
55 | #include <linux/freezer.h> | 55 | #include <linux/freezer.h> |
56 | #include <linux/videodev2.h> | 56 | #include <linux/videodev.h> |
57 | #include <media/v4l2-device.h> | 57 | #include <media/v4l2-device.h> |
58 | #include <media/v4l2-ioctl.h> | 58 | #include <media/v4l2-ioctl.h> |
59 | #include <media/v4l2-i2c-drv-legacy.h> | 59 | #include <media/v4l2-i2c-drv-legacy.h> |
60 | #include <media/msp3400.h> | 60 | #include <media/msp3400.h> |
61 | #include <media/tvaudio.h> | 61 | #include <media/tvaudio.h> |
62 | #include "msp3400-driver.h" | 62 | #include "msp3400-driver.h" |
63 | 63 | ||
64 | /* ---------------------------------------------------------------------- */ | 64 | /* ---------------------------------------------------------------------- */ |
65 | 65 | ||
66 | MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); | 66 | MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); |
67 | MODULE_AUTHOR("Gerd Knorr"); | 67 | MODULE_AUTHOR("Gerd Knorr"); |
68 | MODULE_LICENSE("GPL"); | 68 | MODULE_LICENSE("GPL"); |
69 | 69 | ||
70 | /* module parameters */ | 70 | /* module parameters */ |
71 | static int opmode = OPMODE_AUTO; | 71 | static int opmode = OPMODE_AUTO; |
72 | int msp_debug; /* msp_debug output */ | 72 | int msp_debug; /* msp_debug output */ |
73 | int msp_once; /* no continous stereo monitoring */ | 73 | int msp_once; /* no continous stereo monitoring */ |
74 | int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), | 74 | int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), |
75 | the autoscan seems work well only with FM... */ | 75 | the autoscan seems work well only with FM... */ |
76 | int msp_standard = 1; /* Override auto detect of audio msp_standard, | 76 | int msp_standard = 1; /* Override auto detect of audio msp_standard, |
77 | if needed. */ | 77 | if needed. */ |
78 | int msp_dolby; | 78 | int msp_dolby; |
79 | 79 | ||
80 | int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual | 80 | int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual |
81 | (msp34xxg only) 0x00a0-0x03c0 */ | 81 | (msp34xxg only) 0x00a0-0x03c0 */ |
82 | 82 | ||
83 | /* read-only */ | 83 | /* read-only */ |
84 | module_param(opmode, int, 0444); | 84 | module_param(opmode, int, 0444); |
85 | 85 | ||
86 | /* read-write */ | 86 | /* read-write */ |
87 | module_param_named(once, msp_once, bool, 0644); | 87 | module_param_named(once, msp_once, bool, 0644); |
88 | module_param_named(debug, msp_debug, int, 0644); | 88 | module_param_named(debug, msp_debug, int, 0644); |
89 | module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); | 89 | module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); |
90 | module_param_named(standard, msp_standard, int, 0644); | 90 | module_param_named(standard, msp_standard, int, 0644); |
91 | module_param_named(amsound, msp_amsound, bool, 0644); | 91 | module_param_named(amsound, msp_amsound, bool, 0644); |
92 | module_param_named(dolby, msp_dolby, bool, 0644); | 92 | module_param_named(dolby, msp_dolby, bool, 0644); |
93 | 93 | ||
94 | MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); | 94 | MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); |
95 | MODULE_PARM_DESC(once, "No continuous stereo monitoring"); | 95 | MODULE_PARM_DESC(once, "No continuous stereo monitoring"); |
96 | MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); | 96 | MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); |
97 | MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); | 97 | MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); |
98 | MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); | 98 | MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); |
99 | MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); | 99 | MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); |
100 | MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); | 100 | MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); |
101 | 101 | ||
102 | /* ---------------------------------------------------------------------- */ | 102 | /* ---------------------------------------------------------------------- */ |
103 | 103 | ||
104 | /* control subaddress */ | 104 | /* control subaddress */ |
105 | #define I2C_MSP_CONTROL 0x00 | 105 | #define I2C_MSP_CONTROL 0x00 |
106 | /* demodulator unit subaddress */ | 106 | /* demodulator unit subaddress */ |
107 | #define I2C_MSP_DEM 0x10 | 107 | #define I2C_MSP_DEM 0x10 |
108 | /* DSP unit subaddress */ | 108 | /* DSP unit subaddress */ |
109 | #define I2C_MSP_DSP 0x12 | 109 | #define I2C_MSP_DSP 0x12 |
110 | 110 | ||
111 | /* Addresses to scan */ | 111 | /* Addresses to scan */ |
112 | static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; | 112 | static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; |
113 | 113 | ||
114 | I2C_CLIENT_INSMOD; | 114 | I2C_CLIENT_INSMOD; |
115 | 115 | ||
116 | /* ----------------------------------------------------------------------- */ | 116 | /* ----------------------------------------------------------------------- */ |
117 | /* functions for talking to the MSP3400C Sound processor */ | 117 | /* functions for talking to the MSP3400C Sound processor */ |
118 | 118 | ||
119 | int msp_reset(struct i2c_client *client) | 119 | int msp_reset(struct i2c_client *client) |
120 | { | 120 | { |
121 | /* reset and read revision code */ | 121 | /* reset and read revision code */ |
122 | static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; | 122 | static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; |
123 | static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; | 123 | static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; |
124 | static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; | 124 | static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; |
125 | u8 read[2]; | 125 | u8 read[2]; |
126 | struct i2c_msg reset[2] = { | 126 | struct i2c_msg reset[2] = { |
127 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, | 127 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, |
128 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, | 128 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, |
129 | }; | 129 | }; |
130 | struct i2c_msg test[2] = { | 130 | struct i2c_msg test[2] = { |
131 | { client->addr, 0, 3, write }, | 131 | { client->addr, 0, 3, write }, |
132 | { client->addr, I2C_M_RD, 2, read }, | 132 | { client->addr, I2C_M_RD, 2, read }, |
133 | }; | 133 | }; |
134 | 134 | ||
135 | v4l_dbg(3, msp_debug, client, "msp_reset\n"); | 135 | v4l_dbg(3, msp_debug, client, "msp_reset\n"); |
136 | if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || | 136 | if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || |
137 | i2c_transfer(client->adapter, &reset[1], 1) != 1 || | 137 | i2c_transfer(client->adapter, &reset[1], 1) != 1 || |
138 | i2c_transfer(client->adapter, test, 2) != 2) { | 138 | i2c_transfer(client->adapter, test, 2) != 2) { |
139 | v4l_err(client, "chip reset failed\n"); | 139 | v4l_err(client, "chip reset failed\n"); |
140 | return -1; | 140 | return -1; |
141 | } | 141 | } |
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int msp_read(struct i2c_client *client, int dev, int addr) | 145 | static int msp_read(struct i2c_client *client, int dev, int addr) |
146 | { | 146 | { |
147 | int err, retval; | 147 | int err, retval; |
148 | u8 write[3]; | 148 | u8 write[3]; |
149 | u8 read[2]; | 149 | u8 read[2]; |
150 | struct i2c_msg msgs[2] = { | 150 | struct i2c_msg msgs[2] = { |
151 | { client->addr, 0, 3, write }, | 151 | { client->addr, 0, 3, write }, |
152 | { client->addr, I2C_M_RD, 2, read } | 152 | { client->addr, I2C_M_RD, 2, read } |
153 | }; | 153 | }; |
154 | 154 | ||
155 | write[0] = dev + 1; | 155 | write[0] = dev + 1; |
156 | write[1] = addr >> 8; | 156 | write[1] = addr >> 8; |
157 | write[2] = addr & 0xff; | 157 | write[2] = addr & 0xff; |
158 | 158 | ||
159 | for (err = 0; err < 3; err++) { | 159 | for (err = 0; err < 3; err++) { |
160 | if (i2c_transfer(client->adapter, msgs, 2) == 2) | 160 | if (i2c_transfer(client->adapter, msgs, 2) == 2) |
161 | break; | 161 | break; |
162 | v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, | 162 | v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, |
163 | dev, addr); | 163 | dev, addr); |
164 | schedule_timeout_interruptible(msecs_to_jiffies(10)); | 164 | schedule_timeout_interruptible(msecs_to_jiffies(10)); |
165 | } | 165 | } |
166 | if (err == 3) { | 166 | if (err == 3) { |
167 | v4l_warn(client, "resetting chip, sound will go off.\n"); | 167 | v4l_warn(client, "resetting chip, sound will go off.\n"); |
168 | msp_reset(client); | 168 | msp_reset(client); |
169 | return -1; | 169 | return -1; |
170 | } | 170 | } |
171 | retval = read[0] << 8 | read[1]; | 171 | retval = read[0] << 8 | read[1]; |
172 | v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", | 172 | v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", |
173 | dev, addr, retval); | 173 | dev, addr, retval); |
174 | return retval; | 174 | return retval; |
175 | } | 175 | } |
176 | 176 | ||
177 | int msp_read_dem(struct i2c_client *client, int addr) | 177 | int msp_read_dem(struct i2c_client *client, int addr) |
178 | { | 178 | { |
179 | return msp_read(client, I2C_MSP_DEM, addr); | 179 | return msp_read(client, I2C_MSP_DEM, addr); |
180 | } | 180 | } |
181 | 181 | ||
182 | int msp_read_dsp(struct i2c_client *client, int addr) | 182 | int msp_read_dsp(struct i2c_client *client, int addr) |
183 | { | 183 | { |
184 | return msp_read(client, I2C_MSP_DSP, addr); | 184 | return msp_read(client, I2C_MSP_DSP, addr); |
185 | } | 185 | } |
186 | 186 | ||
187 | static int msp_write(struct i2c_client *client, int dev, int addr, int val) | 187 | static int msp_write(struct i2c_client *client, int dev, int addr, int val) |
188 | { | 188 | { |
189 | int err; | 189 | int err; |
190 | u8 buffer[5]; | 190 | u8 buffer[5]; |
191 | 191 | ||
192 | buffer[0] = dev; | 192 | buffer[0] = dev; |
193 | buffer[1] = addr >> 8; | 193 | buffer[1] = addr >> 8; |
194 | buffer[2] = addr & 0xff; | 194 | buffer[2] = addr & 0xff; |
195 | buffer[3] = val >> 8; | 195 | buffer[3] = val >> 8; |
196 | buffer[4] = val & 0xff; | 196 | buffer[4] = val & 0xff; |
197 | 197 | ||
198 | v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", | 198 | v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", |
199 | dev, addr, val); | 199 | dev, addr, val); |
200 | for (err = 0; err < 3; err++) { | 200 | for (err = 0; err < 3; err++) { |
201 | if (i2c_master_send(client, buffer, 5) == 5) | 201 | if (i2c_master_send(client, buffer, 5) == 5) |
202 | break; | 202 | break; |
203 | v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, | 203 | v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, |
204 | dev, addr); | 204 | dev, addr); |
205 | schedule_timeout_interruptible(msecs_to_jiffies(10)); | 205 | schedule_timeout_interruptible(msecs_to_jiffies(10)); |
206 | } | 206 | } |
207 | if (err == 3) { | 207 | if (err == 3) { |
208 | v4l_warn(client, "resetting chip, sound will go off.\n"); | 208 | v4l_warn(client, "resetting chip, sound will go off.\n"); |
209 | msp_reset(client); | 209 | msp_reset(client); |
210 | return -1; | 210 | return -1; |
211 | } | 211 | } |
212 | return 0; | 212 | return 0; |
213 | } | 213 | } |
214 | 214 | ||
215 | int msp_write_dem(struct i2c_client *client, int addr, int val) | 215 | int msp_write_dem(struct i2c_client *client, int addr, int val) |
216 | { | 216 | { |
217 | return msp_write(client, I2C_MSP_DEM, addr, val); | 217 | return msp_write(client, I2C_MSP_DEM, addr, val); |
218 | } | 218 | } |
219 | 219 | ||
220 | int msp_write_dsp(struct i2c_client *client, int addr, int val) | 220 | int msp_write_dsp(struct i2c_client *client, int addr, int val) |
221 | { | 221 | { |
222 | return msp_write(client, I2C_MSP_DSP, addr, val); | 222 | return msp_write(client, I2C_MSP_DSP, addr, val); |
223 | } | 223 | } |
224 | 224 | ||
225 | /* ----------------------------------------------------------------------- * | 225 | /* ----------------------------------------------------------------------- * |
226 | * bits 9 8 5 - SCART DSP input Select: | 226 | * bits 9 8 5 - SCART DSP input Select: |
227 | * 0 0 0 - SCART 1 to DSP input (reset position) | 227 | * 0 0 0 - SCART 1 to DSP input (reset position) |
228 | * 0 1 0 - MONO to DSP input | 228 | * 0 1 0 - MONO to DSP input |
229 | * 1 0 0 - SCART 2 to DSP input | 229 | * 1 0 0 - SCART 2 to DSP input |
230 | * 1 1 1 - Mute DSP input | 230 | * 1 1 1 - Mute DSP input |
231 | * | 231 | * |
232 | * bits 11 10 6 - SCART 1 Output Select: | 232 | * bits 11 10 6 - SCART 1 Output Select: |
233 | * 0 0 0 - undefined (reset position) | 233 | * 0 0 0 - undefined (reset position) |
234 | * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) | 234 | * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) |
235 | * 1 0 0 - MONO input to SCART 1 Output | 235 | * 1 0 0 - MONO input to SCART 1 Output |
236 | * 1 1 0 - SCART 1 DA to SCART 1 Output | 236 | * 1 1 0 - SCART 1 DA to SCART 1 Output |
237 | * 0 0 1 - SCART 2 DA to SCART 1 Output | 237 | * 0 0 1 - SCART 2 DA to SCART 1 Output |
238 | * 0 1 1 - SCART 1 Input to SCART 1 Output | 238 | * 0 1 1 - SCART 1 Input to SCART 1 Output |
239 | * 1 1 1 - Mute SCART 1 Output | 239 | * 1 1 1 - Mute SCART 1 Output |
240 | * | 240 | * |
241 | * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): | 241 | * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): |
242 | * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) | 242 | * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) |
243 | * 0 1 0 - SCART 1 Input to SCART 2 Output | 243 | * 0 1 0 - SCART 1 Input to SCART 2 Output |
244 | * 1 0 0 - MONO input to SCART 2 Output | 244 | * 1 0 0 - MONO input to SCART 2 Output |
245 | * 0 0 1 - SCART 2 DA to SCART 2 Output | 245 | * 0 0 1 - SCART 2 DA to SCART 2 Output |
246 | * 0 1 1 - SCART 2 Input to SCART 2 Output | 246 | * 0 1 1 - SCART 2 Input to SCART 2 Output |
247 | * 1 1 0 - Mute SCART 2 Output | 247 | * 1 1 0 - Mute SCART 2 Output |
248 | * | 248 | * |
249 | * Bits 4 to 0 should be zero. | 249 | * Bits 4 to 0 should be zero. |
250 | * ----------------------------------------------------------------------- */ | 250 | * ----------------------------------------------------------------------- */ |
251 | 251 | ||
252 | static int scarts[3][9] = { | 252 | static int scarts[3][9] = { |
253 | /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ | 253 | /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ |
254 | /* SCART DSP Input select */ | 254 | /* SCART DSP Input select */ |
255 | { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, | 255 | { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, |
256 | /* SCART1 Output select */ | 256 | /* SCART1 Output select */ |
257 | { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, | 257 | { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, |
258 | /* SCART2 Output select */ | 258 | /* SCART2 Output select */ |
259 | { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, | 259 | { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, |
260 | }; | 260 | }; |
261 | 261 | ||
262 | static char *scart_names[] = { | 262 | static char *scart_names[] = { |
263 | "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" | 263 | "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" |
264 | }; | 264 | }; |
265 | 265 | ||
266 | void msp_set_scart(struct i2c_client *client, int in, int out) | 266 | void msp_set_scart(struct i2c_client *client, int in, int out) |
267 | { | 267 | { |
268 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | 268 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
269 | 269 | ||
270 | state->in_scart = in; | 270 | state->in_scart = in; |
271 | 271 | ||
272 | if (in >= 0 && in <= 7 && out >= 0 && out <= 2) { | 272 | if (in >= 0 && in <= 7 && out >= 0 && out <= 2) { |
273 | if (-1 == scarts[out][in + 1]) | 273 | if (-1 == scarts[out][in + 1]) |
274 | return; | 274 | return; |
275 | 275 | ||
276 | state->acb &= ~scarts[out][0]; | 276 | state->acb &= ~scarts[out][0]; |
277 | state->acb |= scarts[out][in + 1]; | 277 | state->acb |= scarts[out][in + 1]; |
278 | } else | 278 | } else |
279 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ | 279 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ |
280 | 280 | ||
281 | v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", | 281 | v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", |
282 | scart_names[in], out, state->acb); | 282 | scart_names[in], out, state->acb); |
283 | msp_write_dsp(client, 0x13, state->acb); | 283 | msp_write_dsp(client, 0x13, state->acb); |
284 | 284 | ||
285 | /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ | 285 | /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ |
286 | if (state->has_i2s_conf) | 286 | if (state->has_i2s_conf) |
287 | msp_write_dem(client, 0x40, state->i2s_mode); | 287 | msp_write_dem(client, 0x40, state->i2s_mode); |
288 | } | 288 | } |
289 | 289 | ||
290 | void msp_set_audio(struct i2c_client *client) | 290 | void msp_set_audio(struct i2c_client *client) |
291 | { | 291 | { |
292 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | 292 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
293 | int bal = 0, bass, treble, loudness; | 293 | int bal = 0, bass, treble, loudness; |
294 | int val = 0; | 294 | int val = 0; |
295 | int reallymuted = state->muted | state->scan_in_progress; | 295 | int reallymuted = state->muted | state->scan_in_progress; |
296 | 296 | ||
297 | if (!reallymuted) | 297 | if (!reallymuted) |
298 | val = (state->volume * 0x7f / 65535) << 8; | 298 | val = (state->volume * 0x7f / 65535) << 8; |
299 | 299 | ||
300 | v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", | 300 | v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", |
301 | state->muted ? "on" : "off", | 301 | state->muted ? "on" : "off", |
302 | state->scan_in_progress ? "yes" : "no", | 302 | state->scan_in_progress ? "yes" : "no", |
303 | state->volume); | 303 | state->volume); |
304 | 304 | ||
305 | msp_write_dsp(client, 0x0000, val); | 305 | msp_write_dsp(client, 0x0000, val); |
306 | msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); | 306 | msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); |
307 | if (state->has_scart2_out_volume) | 307 | if (state->has_scart2_out_volume) |
308 | msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); | 308 | msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); |
309 | if (state->has_headphones) | 309 | if (state->has_headphones) |
310 | msp_write_dsp(client, 0x0006, val); | 310 | msp_write_dsp(client, 0x0006, val); |
311 | if (!state->has_sound_processing) | 311 | if (!state->has_sound_processing) |
312 | return; | 312 | return; |
313 | 313 | ||
314 | if (val) | 314 | if (val) |
315 | bal = (u8)((state->balance / 256) - 128); | 315 | bal = (u8)((state->balance / 256) - 128); |
316 | bass = ((state->bass - 32768) * 0x60 / 65535) << 8; | 316 | bass = ((state->bass - 32768) * 0x60 / 65535) << 8; |
317 | treble = ((state->treble - 32768) * 0x60 / 65535) << 8; | 317 | treble = ((state->treble - 32768) * 0x60 / 65535) << 8; |
318 | loudness = state->loudness ? ((5 * 4) << 8) : 0; | 318 | loudness = state->loudness ? ((5 * 4) << 8) : 0; |
319 | 319 | ||
320 | v4l_dbg(1, msp_debug, client, "balance=%d bass=%d treble=%d loudness=%d\n", | 320 | v4l_dbg(1, msp_debug, client, "balance=%d bass=%d treble=%d loudness=%d\n", |
321 | state->balance, state->bass, state->treble, state->loudness); | 321 | state->balance, state->bass, state->treble, state->loudness); |
322 | 322 | ||
323 | msp_write_dsp(client, 0x0001, bal << 8); | 323 | msp_write_dsp(client, 0x0001, bal << 8); |
324 | msp_write_dsp(client, 0x0002, bass); | 324 | msp_write_dsp(client, 0x0002, bass); |
325 | msp_write_dsp(client, 0x0003, treble); | 325 | msp_write_dsp(client, 0x0003, treble); |
326 | msp_write_dsp(client, 0x0004, loudness); | 326 | msp_write_dsp(client, 0x0004, loudness); |
327 | if (!state->has_headphones) | 327 | if (!state->has_headphones) |
328 | return; | 328 | return; |
329 | msp_write_dsp(client, 0x0030, bal << 8); | 329 | msp_write_dsp(client, 0x0030, bal << 8); |
330 | msp_write_dsp(client, 0x0031, bass); | 330 | msp_write_dsp(client, 0x0031, bass); |
331 | msp_write_dsp(client, 0x0032, treble); | 331 | msp_write_dsp(client, 0x0032, treble); |
332 | msp_write_dsp(client, 0x0033, loudness); | 332 | msp_write_dsp(client, 0x0033, loudness); |
333 | } | 333 | } |
334 | 334 | ||
335 | /* ------------------------------------------------------------------------ */ | 335 | /* ------------------------------------------------------------------------ */ |
336 | 336 | ||
337 | static void msp_wake_thread(struct i2c_client *client) | 337 | static void msp_wake_thread(struct i2c_client *client) |
338 | { | 338 | { |
339 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | 339 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
340 | 340 | ||
341 | if (NULL == state->kthread) | 341 | if (NULL == state->kthread) |
342 | return; | 342 | return; |
343 | state->watch_stereo = 0; | 343 | state->watch_stereo = 0; |
344 | state->restart = 1; | 344 | state->restart = 1; |
345 | wake_up_interruptible(&state->wq); | 345 | wake_up_interruptible(&state->wq); |
346 | } | 346 | } |
347 | 347 | ||
348 | int msp_sleep(struct msp_state *state, int timeout) | 348 | int msp_sleep(struct msp_state *state, int timeout) |
349 | { | 349 | { |
350 | DECLARE_WAITQUEUE(wait, current); | 350 | DECLARE_WAITQUEUE(wait, current); |
351 | 351 | ||
352 | add_wait_queue(&state->wq, &wait); | 352 | add_wait_queue(&state->wq, &wait); |
353 | if (!kthread_should_stop()) { | 353 | if (!kthread_should_stop()) { |
354 | if (timeout < 0) { | 354 | if (timeout < 0) { |
355 | set_current_state(TASK_INTERRUPTIBLE); | 355 | set_current_state(TASK_INTERRUPTIBLE); |
356 | schedule(); | 356 | schedule(); |
357 | } else { | 357 | } else { |
358 | schedule_timeout_interruptible | 358 | schedule_timeout_interruptible |
359 | (msecs_to_jiffies(timeout)); | 359 | (msecs_to_jiffies(timeout)); |
360 | } | 360 | } |
361 | } | 361 | } |
362 | 362 | ||
363 | remove_wait_queue(&state->wq, &wait); | 363 | remove_wait_queue(&state->wq, &wait); |
364 | try_to_freeze(); | 364 | try_to_freeze(); |
365 | return state->restart; | 365 | return state->restart; |
366 | } | 366 | } |
367 | 367 | ||
368 | /* ------------------------------------------------------------------------ */ | 368 | /* ------------------------------------------------------------------------ */ |
369 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | 369 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 |
370 | static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) | 370 | static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) |
371 | { | 371 | { |
372 | if (rxsubchans == V4L2_TUNER_SUB_MONO) | 372 | if (rxsubchans == V4L2_TUNER_SUB_MONO) |
373 | return VIDEO_SOUND_MONO; | 373 | return VIDEO_SOUND_MONO; |
374 | if (rxsubchans == V4L2_TUNER_SUB_STEREO) | 374 | if (rxsubchans == V4L2_TUNER_SUB_STEREO) |
375 | return VIDEO_SOUND_STEREO; | 375 | return VIDEO_SOUND_STEREO; |
376 | if (audmode == V4L2_TUNER_MODE_LANG2) | 376 | if (audmode == V4L2_TUNER_MODE_LANG2) |
377 | return VIDEO_SOUND_LANG2; | 377 | return VIDEO_SOUND_LANG2; |
378 | return VIDEO_SOUND_LANG1; | 378 | return VIDEO_SOUND_LANG1; |
379 | } | 379 | } |
380 | 380 | ||
381 | static int msp_mode_v4l1_to_v4l2(int mode) | 381 | static int msp_mode_v4l1_to_v4l2(int mode) |
382 | { | 382 | { |
383 | if (mode & VIDEO_SOUND_STEREO) | 383 | if (mode & VIDEO_SOUND_STEREO) |
384 | return V4L2_TUNER_MODE_STEREO; | 384 | return V4L2_TUNER_MODE_STEREO; |
385 | if (mode & VIDEO_SOUND_LANG2) | 385 | if (mode & VIDEO_SOUND_LANG2) |
386 | return V4L2_TUNER_MODE_LANG2; | 386 | return V4L2_TUNER_MODE_LANG2; |
387 | if (mode & VIDEO_SOUND_LANG1) | 387 | if (mode & VIDEO_SOUND_LANG1) |
388 | return V4L2_TUNER_MODE_LANG1; | 388 | return V4L2_TUNER_MODE_LANG1; |
389 | return V4L2_TUNER_MODE_MONO; | 389 | return V4L2_TUNER_MODE_MONO; |
390 | } | 390 | } |
391 | #endif | 391 | #endif |
392 | 392 | ||
393 | static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 393 | static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
394 | { | 394 | { |
395 | struct msp_state *state = to_state(sd); | 395 | struct msp_state *state = to_state(sd); |
396 | 396 | ||
397 | switch (ctrl->id) { | 397 | switch (ctrl->id) { |
398 | case V4L2_CID_AUDIO_VOLUME: | 398 | case V4L2_CID_AUDIO_VOLUME: |
399 | ctrl->value = state->volume; | 399 | ctrl->value = state->volume; |
400 | break; | 400 | break; |
401 | 401 | ||
402 | case V4L2_CID_AUDIO_MUTE: | 402 | case V4L2_CID_AUDIO_MUTE: |
403 | ctrl->value = state->muted; | 403 | ctrl->value = state->muted; |
404 | break; | 404 | break; |
405 | 405 | ||
406 | case V4L2_CID_AUDIO_BALANCE: | 406 | case V4L2_CID_AUDIO_BALANCE: |
407 | if (!state->has_sound_processing) | 407 | if (!state->has_sound_processing) |
408 | return -EINVAL; | 408 | return -EINVAL; |
409 | ctrl->value = state->balance; | 409 | ctrl->value = state->balance; |
410 | break; | 410 | break; |
411 | 411 | ||
412 | case V4L2_CID_AUDIO_BASS: | 412 | case V4L2_CID_AUDIO_BASS: |
413 | if (!state->has_sound_processing) | 413 | if (!state->has_sound_processing) |
414 | return -EINVAL; | 414 | return -EINVAL; |
415 | ctrl->value = state->bass; | 415 | ctrl->value = state->bass; |
416 | break; | 416 | break; |
417 | 417 | ||
418 | case V4L2_CID_AUDIO_TREBLE: | 418 | case V4L2_CID_AUDIO_TREBLE: |
419 | if (!state->has_sound_processing) | 419 | if (!state->has_sound_processing) |
420 | return -EINVAL; | 420 | return -EINVAL; |
421 | ctrl->value = state->treble; | 421 | ctrl->value = state->treble; |
422 | break; | 422 | break; |
423 | 423 | ||
424 | case V4L2_CID_AUDIO_LOUDNESS: | 424 | case V4L2_CID_AUDIO_LOUDNESS: |
425 | if (!state->has_sound_processing) | 425 | if (!state->has_sound_processing) |
426 | return -EINVAL; | 426 | return -EINVAL; |
427 | ctrl->value = state->loudness; | 427 | ctrl->value = state->loudness; |
428 | break; | 428 | break; |
429 | 429 | ||
430 | default: | 430 | default: |
431 | return -EINVAL; | 431 | return -EINVAL; |
432 | } | 432 | } |
433 | return 0; | 433 | return 0; |
434 | } | 434 | } |
435 | 435 | ||
436 | static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 436 | static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
437 | { | 437 | { |
438 | struct msp_state *state = to_state(sd); | 438 | struct msp_state *state = to_state(sd); |
439 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 439 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
440 | 440 | ||
441 | switch (ctrl->id) { | 441 | switch (ctrl->id) { |
442 | case V4L2_CID_AUDIO_VOLUME: | 442 | case V4L2_CID_AUDIO_VOLUME: |
443 | state->volume = ctrl->value; | 443 | state->volume = ctrl->value; |
444 | if (state->volume == 0) | 444 | if (state->volume == 0) |
445 | state->balance = 32768; | 445 | state->balance = 32768; |
446 | break; | 446 | break; |
447 | 447 | ||
448 | case V4L2_CID_AUDIO_MUTE: | 448 | case V4L2_CID_AUDIO_MUTE: |
449 | if (ctrl->value < 0 || ctrl->value >= 2) | 449 | if (ctrl->value < 0 || ctrl->value >= 2) |
450 | return -ERANGE; | 450 | return -ERANGE; |
451 | state->muted = ctrl->value; | 451 | state->muted = ctrl->value; |
452 | break; | 452 | break; |
453 | 453 | ||
454 | case V4L2_CID_AUDIO_BASS: | 454 | case V4L2_CID_AUDIO_BASS: |
455 | if (!state->has_sound_processing) | 455 | if (!state->has_sound_processing) |
456 | return -EINVAL; | 456 | return -EINVAL; |
457 | state->bass = ctrl->value; | 457 | state->bass = ctrl->value; |
458 | break; | 458 | break; |
459 | 459 | ||
460 | case V4L2_CID_AUDIO_TREBLE: | 460 | case V4L2_CID_AUDIO_TREBLE: |
461 | if (!state->has_sound_processing) | 461 | if (!state->has_sound_processing) |
462 | return -EINVAL; | 462 | return -EINVAL; |
463 | state->treble = ctrl->value; | 463 | state->treble = ctrl->value; |
464 | break; | 464 | break; |
465 | 465 | ||
466 | case V4L2_CID_AUDIO_LOUDNESS: | 466 | case V4L2_CID_AUDIO_LOUDNESS: |
467 | if (!state->has_sound_processing) | 467 | if (!state->has_sound_processing) |
468 | return -EINVAL; | 468 | return -EINVAL; |
469 | state->loudness = ctrl->value; | 469 | state->loudness = ctrl->value; |
470 | break; | 470 | break; |
471 | 471 | ||
472 | case V4L2_CID_AUDIO_BALANCE: | 472 | case V4L2_CID_AUDIO_BALANCE: |
473 | if (!state->has_sound_processing) | 473 | if (!state->has_sound_processing) |
474 | return -EINVAL; | 474 | return -EINVAL; |
475 | state->balance = ctrl->value; | 475 | state->balance = ctrl->value; |
476 | break; | 476 | break; |
477 | 477 | ||
478 | default: | 478 | default: |
479 | return -EINVAL; | 479 | return -EINVAL; |
480 | } | 480 | } |
481 | msp_set_audio(client); | 481 | msp_set_audio(client); |
482 | return 0; | 482 | return 0; |
483 | } | 483 | } |
484 | 484 | ||
485 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | 485 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 |
486 | static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) | 486 | static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
487 | { | 487 | { |
488 | struct msp_state *state = to_state(sd); | 488 | struct msp_state *state = to_state(sd); |
489 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 489 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
490 | 490 | ||
491 | switch (cmd) { | 491 | switch (cmd) { |
492 | /* --- v4l ioctls --- */ | 492 | /* --- v4l ioctls --- */ |
493 | /* take care: bttv does userspace copying, we'll get a | 493 | /* take care: bttv does userspace copying, we'll get a |
494 | kernel pointer here... */ | 494 | kernel pointer here... */ |
495 | case VIDIOCGAUDIO: | 495 | case VIDIOCGAUDIO: |
496 | { | 496 | { |
497 | struct video_audio *va = arg; | 497 | struct video_audio *va = arg; |
498 | 498 | ||
499 | va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE; | 499 | va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE; |
500 | if (state->has_sound_processing) | 500 | if (state->has_sound_processing) |
501 | va->flags |= VIDEO_AUDIO_BALANCE | | 501 | va->flags |= VIDEO_AUDIO_BALANCE | |
502 | VIDEO_AUDIO_BASS | | 502 | VIDEO_AUDIO_BASS | |
503 | VIDEO_AUDIO_TREBLE; | 503 | VIDEO_AUDIO_TREBLE; |
504 | if (state->muted) | 504 | if (state->muted) |
505 | va->flags |= VIDEO_AUDIO_MUTE; | 505 | va->flags |= VIDEO_AUDIO_MUTE; |
506 | va->volume = state->volume; | 506 | va->volume = state->volume; |
507 | va->balance = state->volume ? state->balance : 32768; | 507 | va->balance = state->volume ? state->balance : 32768; |
508 | va->bass = state->bass; | 508 | va->bass = state->bass; |
509 | va->treble = state->treble; | 509 | va->treble = state->treble; |
510 | 510 | ||
511 | if (state->radio) | 511 | if (state->radio) |
512 | break; | 512 | break; |
513 | if (state->opmode == OPMODE_AUTOSELECT) | 513 | if (state->opmode == OPMODE_AUTOSELECT) |
514 | msp_detect_stereo(client); | 514 | msp_detect_stereo(client); |
515 | va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode); | 515 | va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode); |
516 | break; | 516 | break; |
517 | } | 517 | } |
518 | 518 | ||
519 | case VIDIOCSAUDIO: | 519 | case VIDIOCSAUDIO: |
520 | { | 520 | { |
521 | struct video_audio *va = arg; | 521 | struct video_audio *va = arg; |
522 | 522 | ||
523 | state->muted = (va->flags & VIDEO_AUDIO_MUTE); | 523 | state->muted = (va->flags & VIDEO_AUDIO_MUTE); |
524 | state->volume = va->volume; | 524 | state->volume = va->volume; |
525 | state->balance = va->balance; | 525 | state->balance = va->balance; |
526 | state->bass = va->bass; | 526 | state->bass = va->bass; |
527 | state->treble = va->treble; | 527 | state->treble = va->treble; |
528 | msp_set_audio(client); | 528 | msp_set_audio(client); |
529 | 529 | ||
530 | if (va->mode != 0 && state->radio == 0 && | 530 | if (va->mode != 0 && state->radio == 0 && |
531 | state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) { | 531 | state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) { |
532 | state->audmode = msp_mode_v4l1_to_v4l2(va->mode); | 532 | state->audmode = msp_mode_v4l1_to_v4l2(va->mode); |
533 | msp_set_audmode(client); | 533 | msp_set_audmode(client); |
534 | } | 534 | } |
535 | break; | 535 | break; |
536 | } | 536 | } |
537 | 537 | ||
538 | case VIDIOCSCHAN: | 538 | case VIDIOCSCHAN: |
539 | { | 539 | { |
540 | struct video_channel *vc = arg; | 540 | struct video_channel *vc = arg; |
541 | int update = 0; | 541 | int update = 0; |
542 | v4l2_std_id std; | 542 | v4l2_std_id std; |
543 | 543 | ||
544 | if (state->radio) | 544 | if (state->radio) |
545 | update = 1; | 545 | update = 1; |
546 | state->radio = 0; | 546 | state->radio = 0; |
547 | if (vc->norm == VIDEO_MODE_PAL) | 547 | if (vc->norm == VIDEO_MODE_PAL) |
548 | std = V4L2_STD_PAL; | 548 | std = V4L2_STD_PAL; |
549 | else if (vc->norm == VIDEO_MODE_SECAM) | 549 | else if (vc->norm == VIDEO_MODE_SECAM) |
550 | std = V4L2_STD_SECAM; | 550 | std = V4L2_STD_SECAM; |
551 | else | 551 | else |
552 | std = V4L2_STD_NTSC; | 552 | std = V4L2_STD_NTSC; |
553 | if (std != state->v4l2_std) { | 553 | if (std != state->v4l2_std) { |
554 | state->v4l2_std = std; | 554 | state->v4l2_std = std; |
555 | update = 1; | 555 | update = 1; |
556 | } | 556 | } |
557 | if (update) | 557 | if (update) |
558 | msp_wake_thread(client); | 558 | msp_wake_thread(client); |
559 | break; | 559 | break; |
560 | } | 560 | } |
561 | 561 | ||
562 | case VIDIOCSFREQ: | 562 | case VIDIOCSFREQ: |
563 | { | 563 | { |
564 | /* new channel -- kick audio carrier scan */ | 564 | /* new channel -- kick audio carrier scan */ |
565 | msp_wake_thread(client); | 565 | msp_wake_thread(client); |
566 | break; | 566 | break; |
567 | } | 567 | } |
568 | default: | 568 | default: |
569 | return -ENOIOCTLCMD; | 569 | return -ENOIOCTLCMD; |
570 | } | 570 | } |
571 | return 0; | 571 | return 0; |
572 | } | 572 | } |
573 | #endif | 573 | #endif |
574 | 574 | ||
575 | /* --- v4l2 ioctls --- */ | 575 | /* --- v4l2 ioctls --- */ |
576 | static int msp_s_radio(struct v4l2_subdev *sd) | 576 | static int msp_s_radio(struct v4l2_subdev *sd) |
577 | { | 577 | { |
578 | struct msp_state *state = to_state(sd); | 578 | struct msp_state *state = to_state(sd); |
579 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 579 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
580 | 580 | ||
581 | if (state->radio) | 581 | if (state->radio) |
582 | return 0; | 582 | return 0; |
583 | state->radio = 1; | 583 | state->radio = 1; |
584 | v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); | 584 | v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); |
585 | state->watch_stereo = 0; | 585 | state->watch_stereo = 0; |
586 | switch (state->opmode) { | 586 | switch (state->opmode) { |
587 | case OPMODE_MANUAL: | 587 | case OPMODE_MANUAL: |
588 | /* set msp3400 to FM radio mode */ | 588 | /* set msp3400 to FM radio mode */ |
589 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); | 589 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); |
590 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), | 590 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), |
591 | MSP_CARRIER(10.7)); | 591 | MSP_CARRIER(10.7)); |
592 | msp_set_audio(client); | 592 | msp_set_audio(client); |
593 | break; | 593 | break; |
594 | case OPMODE_AUTODETECT: | 594 | case OPMODE_AUTODETECT: |
595 | case OPMODE_AUTOSELECT: | 595 | case OPMODE_AUTOSELECT: |
596 | /* the thread will do for us */ | 596 | /* the thread will do for us */ |
597 | msp_wake_thread(client); | 597 | msp_wake_thread(client); |
598 | break; | 598 | break; |
599 | } | 599 | } |
600 | return 0; | 600 | return 0; |
601 | } | 601 | } |
602 | 602 | ||
603 | static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) | 603 | static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) |
604 | { | 604 | { |
605 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 605 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
606 | 606 | ||
607 | /* new channel -- kick audio carrier scan */ | 607 | /* new channel -- kick audio carrier scan */ |
608 | msp_wake_thread(client); | 608 | msp_wake_thread(client); |
609 | return 0; | 609 | return 0; |
610 | } | 610 | } |
611 | 611 | ||
612 | static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) | 612 | static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) |
613 | { | 613 | { |
614 | struct msp_state *state = to_state(sd); | 614 | struct msp_state *state = to_state(sd); |
615 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 615 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
616 | int update = state->radio || state->v4l2_std != id; | 616 | int update = state->radio || state->v4l2_std != id; |
617 | 617 | ||
618 | state->v4l2_std = id; | 618 | state->v4l2_std = id; |
619 | state->radio = 0; | 619 | state->radio = 0; |
620 | if (update) | 620 | if (update) |
621 | msp_wake_thread(client); | 621 | msp_wake_thread(client); |
622 | return 0; | 622 | return 0; |
623 | } | 623 | } |
624 | 624 | ||
625 | static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt) | 625 | static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt) |
626 | { | 626 | { |
627 | struct msp_state *state = to_state(sd); | 627 | struct msp_state *state = to_state(sd); |
628 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 628 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
629 | int tuner = (rt->input >> 3) & 1; | 629 | int tuner = (rt->input >> 3) & 1; |
630 | int sc_in = rt->input & 0x7; | 630 | int sc_in = rt->input & 0x7; |
631 | int sc1_out = rt->output & 0xf; | 631 | int sc1_out = rt->output & 0xf; |
632 | int sc2_out = (rt->output >> 4) & 0xf; | 632 | int sc2_out = (rt->output >> 4) & 0xf; |
633 | u16 val, reg; | 633 | u16 val, reg; |
634 | int i; | 634 | int i; |
635 | int extern_input = 1; | 635 | int extern_input = 1; |
636 | 636 | ||
637 | if (state->routing.input == rt->input && | 637 | if (state->routing.input == rt->input && |
638 | state->routing.output == rt->output) | 638 | state->routing.output == rt->output) |
639 | return 0; | 639 | return 0; |
640 | state->routing = *rt; | 640 | state->routing = *rt; |
641 | /* check if the tuner input is used */ | 641 | /* check if the tuner input is used */ |
642 | for (i = 0; i < 5; i++) { | 642 | for (i = 0; i < 5; i++) { |
643 | if (((rt->input >> (4 + i * 4)) & 0xf) == 0) | 643 | if (((rt->input >> (4 + i * 4)) & 0xf) == 0) |
644 | extern_input = 0; | 644 | extern_input = 0; |
645 | } | 645 | } |
646 | state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; | 646 | state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; |
647 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | 647 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; |
648 | msp_set_scart(client, sc_in, 0); | 648 | msp_set_scart(client, sc_in, 0); |
649 | msp_set_scart(client, sc1_out, 1); | 649 | msp_set_scart(client, sc1_out, 1); |
650 | msp_set_scart(client, sc2_out, 2); | 650 | msp_set_scart(client, sc2_out, 2); |
651 | msp_set_audmode(client); | 651 | msp_set_audmode(client); |
652 | reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; | 652 | reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; |
653 | val = msp_read_dem(client, reg); | 653 | val = msp_read_dem(client, reg); |
654 | msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); | 654 | msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); |
655 | /* wake thread when a new input is chosen */ | 655 | /* wake thread when a new input is chosen */ |
656 | msp_wake_thread(client); | 656 | msp_wake_thread(client); |
657 | return 0; | 657 | return 0; |
658 | } | 658 | } |
659 | 659 | ||
660 | static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | 660 | static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
661 | { | 661 | { |
662 | struct msp_state *state = to_state(sd); | 662 | struct msp_state *state = to_state(sd); |
663 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 663 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
664 | 664 | ||
665 | if (state->radio) | 665 | if (state->radio) |
666 | return 0; | 666 | return 0; |
667 | if (state->opmode == OPMODE_AUTOSELECT) | 667 | if (state->opmode == OPMODE_AUTOSELECT) |
668 | msp_detect_stereo(client); | 668 | msp_detect_stereo(client); |
669 | vt->audmode = state->audmode; | 669 | vt->audmode = state->audmode; |
670 | vt->rxsubchans = state->rxsubchans; | 670 | vt->rxsubchans = state->rxsubchans; |
671 | vt->capability |= V4L2_TUNER_CAP_STEREO | | 671 | vt->capability |= V4L2_TUNER_CAP_STEREO | |
672 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | 672 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; |
673 | return 0; | 673 | return 0; |
674 | } | 674 | } |
675 | 675 | ||
676 | static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | 676 | static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
677 | { | 677 | { |
678 | struct msp_state *state = to_state(sd); | 678 | struct msp_state *state = to_state(sd); |
679 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 679 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
680 | 680 | ||
681 | if (state->radio) /* TODO: add mono/stereo support for radio */ | 681 | if (state->radio) /* TODO: add mono/stereo support for radio */ |
682 | return 0; | 682 | return 0; |
683 | if (state->audmode == vt->audmode) | 683 | if (state->audmode == vt->audmode) |
684 | return 0; | 684 | return 0; |
685 | state->audmode = vt->audmode; | 685 | state->audmode = vt->audmode; |
686 | /* only set audmode */ | 686 | /* only set audmode */ |
687 | msp_set_audmode(client); | 687 | msp_set_audmode(client); |
688 | return 0; | 688 | return 0; |
689 | } | 689 | } |
690 | 690 | ||
691 | static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) | 691 | static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) |
692 | { | 692 | { |
693 | struct msp_state *state = to_state(sd); | 693 | struct msp_state *state = to_state(sd); |
694 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 694 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
695 | 695 | ||
696 | v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); | 696 | v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); |
697 | 697 | ||
698 | switch (freq) { | 698 | switch (freq) { |
699 | case 1024000: | 699 | case 1024000: |
700 | state->i2s_mode = 0; | 700 | state->i2s_mode = 0; |
701 | break; | 701 | break; |
702 | case 2048000: | 702 | case 2048000: |
703 | state->i2s_mode = 1; | 703 | state->i2s_mode = 1; |
704 | break; | 704 | break; |
705 | default: | 705 | default: |
706 | return -EINVAL; | 706 | return -EINVAL; |
707 | } | 707 | } |
708 | return 0; | 708 | return 0; |
709 | } | 709 | } |
710 | 710 | ||
711 | static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | 711 | static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) |
712 | { | 712 | { |
713 | struct msp_state *state = to_state(sd); | 713 | struct msp_state *state = to_state(sd); |
714 | 714 | ||
715 | switch (qc->id) { | 715 | switch (qc->id) { |
716 | case V4L2_CID_AUDIO_VOLUME: | 716 | case V4L2_CID_AUDIO_VOLUME: |
717 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); | 717 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); |
718 | case V4L2_CID_AUDIO_MUTE: | 718 | case V4L2_CID_AUDIO_MUTE: |
719 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | 719 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); |
720 | default: | 720 | default: |
721 | break; | 721 | break; |
722 | } | 722 | } |
723 | if (!state->has_sound_processing) | 723 | if (!state->has_sound_processing) |
724 | return -EINVAL; | 724 | return -EINVAL; |
725 | switch (qc->id) { | 725 | switch (qc->id) { |
726 | case V4L2_CID_AUDIO_LOUDNESS: | 726 | case V4L2_CID_AUDIO_LOUDNESS: |
727 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | 727 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); |
728 | case V4L2_CID_AUDIO_BALANCE: | 728 | case V4L2_CID_AUDIO_BALANCE: |
729 | case V4L2_CID_AUDIO_BASS: | 729 | case V4L2_CID_AUDIO_BASS: |
730 | case V4L2_CID_AUDIO_TREBLE: | 730 | case V4L2_CID_AUDIO_TREBLE: |
731 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | 731 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); |
732 | default: | 732 | default: |
733 | return -EINVAL; | 733 | return -EINVAL; |
734 | } | 734 | } |
735 | return 0; | 735 | return 0; |
736 | } | 736 | } |
737 | 737 | ||
738 | static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 738 | static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
739 | { | 739 | { |
740 | struct msp_state *state = to_state(sd); | 740 | struct msp_state *state = to_state(sd); |
741 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 741 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
742 | 742 | ||
743 | return v4l2_chip_ident_i2c_client(client, chip, state->ident, | 743 | return v4l2_chip_ident_i2c_client(client, chip, state->ident, |
744 | (state->rev1 << 16) | state->rev2); | 744 | (state->rev1 << 16) | state->rev2); |
745 | } | 745 | } |
746 | 746 | ||
747 | static int msp_log_status(struct v4l2_subdev *sd) | 747 | static int msp_log_status(struct v4l2_subdev *sd) |
748 | { | 748 | { |
749 | struct msp_state *state = to_state(sd); | 749 | struct msp_state *state = to_state(sd); |
750 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 750 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
751 | const char *p; | 751 | const char *p; |
752 | 752 | ||
753 | if (state->opmode == OPMODE_AUTOSELECT) | 753 | if (state->opmode == OPMODE_AUTOSELECT) |
754 | msp_detect_stereo(client); | 754 | msp_detect_stereo(client); |
755 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", | 755 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", |
756 | client->name, state->rev1, state->rev2); | 756 | client->name, state->rev1, state->rev2); |
757 | v4l_info(client, "Audio: volume %d%s\n", | 757 | v4l_info(client, "Audio: volume %d%s\n", |
758 | state->volume, state->muted ? " (muted)" : ""); | 758 | state->volume, state->muted ? " (muted)" : ""); |
759 | if (state->has_sound_processing) { | 759 | if (state->has_sound_processing) { |
760 | v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", | 760 | v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", |
761 | state->balance, state->bass, | 761 | state->balance, state->bass, |
762 | state->treble, | 762 | state->treble, |
763 | state->loudness ? "on" : "off"); | 763 | state->loudness ? "on" : "off"); |
764 | } | 764 | } |
765 | switch (state->mode) { | 765 | switch (state->mode) { |
766 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; | 766 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; |
767 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; | 767 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; |
768 | case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; | 768 | case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; |
769 | case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; | 769 | case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; |
770 | case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; | 770 | case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; |
771 | case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; | 771 | case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; |
772 | case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break; | 772 | case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break; |
773 | case MSP_MODE_BTSC: p = "BTSC"; break; | 773 | case MSP_MODE_BTSC: p = "BTSC"; break; |
774 | case MSP_MODE_EXTERN: p = "External input"; break; | 774 | case MSP_MODE_EXTERN: p = "External input"; break; |
775 | default: p = "unknown"; break; | 775 | default: p = "unknown"; break; |
776 | } | 776 | } |
777 | if (state->mode == MSP_MODE_EXTERN) { | 777 | if (state->mode == MSP_MODE_EXTERN) { |
778 | v4l_info(client, "Mode: %s\n", p); | 778 | v4l_info(client, "Mode: %s\n", p); |
779 | } else if (state->opmode == OPMODE_MANUAL) { | 779 | } else if (state->opmode == OPMODE_MANUAL) { |
780 | v4l_info(client, "Mode: %s (%s%s)\n", p, | 780 | v4l_info(client, "Mode: %s (%s%s)\n", p, |
781 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 781 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
782 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 782 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
783 | } else { | 783 | } else { |
784 | if (state->opmode == OPMODE_AUTODETECT) | 784 | if (state->opmode == OPMODE_AUTODETECT) |
785 | v4l_info(client, "Mode: %s\n", p); | 785 | v4l_info(client, "Mode: %s\n", p); |
786 | v4l_info(client, "Standard: %s (%s%s)\n", | 786 | v4l_info(client, "Standard: %s (%s%s)\n", |
787 | msp_standard_std_name(state->std), | 787 | msp_standard_std_name(state->std), |
788 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 788 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
789 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 789 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
790 | } | 790 | } |
791 | v4l_info(client, "Audmode: 0x%04x\n", state->audmode); | 791 | v4l_info(client, "Audmode: 0x%04x\n", state->audmode); |
792 | v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", | 792 | v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", |
793 | state->routing.input, state->routing.output); | 793 | state->routing.input, state->routing.output); |
794 | v4l_info(client, "ACB: 0x%04x\n", state->acb); | 794 | v4l_info(client, "ACB: 0x%04x\n", state->acb); |
795 | return 0; | 795 | return 0; |
796 | } | 796 | } |
797 | 797 | ||
798 | static int msp_suspend(struct i2c_client *client, pm_message_t state) | 798 | static int msp_suspend(struct i2c_client *client, pm_message_t state) |
799 | { | 799 | { |
800 | v4l_dbg(1, msp_debug, client, "suspend\n"); | 800 | v4l_dbg(1, msp_debug, client, "suspend\n"); |
801 | msp_reset(client); | 801 | msp_reset(client); |
802 | return 0; | 802 | return 0; |
803 | } | 803 | } |
804 | 804 | ||
805 | static int msp_resume(struct i2c_client *client) | 805 | static int msp_resume(struct i2c_client *client) |
806 | { | 806 | { |
807 | v4l_dbg(1, msp_debug, client, "resume\n"); | 807 | v4l_dbg(1, msp_debug, client, "resume\n"); |
808 | msp_wake_thread(client); | 808 | msp_wake_thread(client); |
809 | return 0; | 809 | return 0; |
810 | } | 810 | } |
811 | 811 | ||
812 | static int msp_command(struct i2c_client *client, unsigned cmd, void *arg) | 812 | static int msp_command(struct i2c_client *client, unsigned cmd, void *arg) |
813 | { | 813 | { |
814 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | 814 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); |
815 | } | 815 | } |
816 | 816 | ||
817 | /* ----------------------------------------------------------------------- */ | 817 | /* ----------------------------------------------------------------------- */ |
818 | 818 | ||
819 | static const struct v4l2_subdev_core_ops msp_core_ops = { | 819 | static const struct v4l2_subdev_core_ops msp_core_ops = { |
820 | .log_status = msp_log_status, | 820 | .log_status = msp_log_status, |
821 | .g_chip_ident = msp_g_chip_ident, | 821 | .g_chip_ident = msp_g_chip_ident, |
822 | .g_ctrl = msp_g_ctrl, | 822 | .g_ctrl = msp_g_ctrl, |
823 | .s_ctrl = msp_s_ctrl, | 823 | .s_ctrl = msp_s_ctrl, |
824 | .queryctrl = msp_queryctrl, | 824 | .queryctrl = msp_queryctrl, |
825 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | 825 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 |
826 | .ioctl = msp_ioctl, | 826 | .ioctl = msp_ioctl, |
827 | #endif | 827 | #endif |
828 | }; | 828 | }; |
829 | 829 | ||
830 | static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { | 830 | static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { |
831 | .s_frequency = msp_s_frequency, | 831 | .s_frequency = msp_s_frequency, |
832 | .g_tuner = msp_g_tuner, | 832 | .g_tuner = msp_g_tuner, |
833 | .s_tuner = msp_s_tuner, | 833 | .s_tuner = msp_s_tuner, |
834 | .s_radio = msp_s_radio, | 834 | .s_radio = msp_s_radio, |
835 | .s_std = msp_s_std, | 835 | .s_std = msp_s_std, |
836 | }; | 836 | }; |
837 | 837 | ||
838 | static const struct v4l2_subdev_audio_ops msp_audio_ops = { | 838 | static const struct v4l2_subdev_audio_ops msp_audio_ops = { |
839 | .s_routing = msp_s_routing, | 839 | .s_routing = msp_s_routing, |
840 | .s_i2s_clock_freq = msp_s_i2s_clock_freq, | 840 | .s_i2s_clock_freq = msp_s_i2s_clock_freq, |
841 | }; | 841 | }; |
842 | 842 | ||
843 | static const struct v4l2_subdev_ops msp_ops = { | 843 | static const struct v4l2_subdev_ops msp_ops = { |
844 | .core = &msp_core_ops, | 844 | .core = &msp_core_ops, |
845 | .tuner = &msp_tuner_ops, | 845 | .tuner = &msp_tuner_ops, |
846 | .audio = &msp_audio_ops, | 846 | .audio = &msp_audio_ops, |
847 | }; | 847 | }; |
848 | 848 | ||
849 | /* ----------------------------------------------------------------------- */ | 849 | /* ----------------------------------------------------------------------- */ |
850 | 850 | ||
851 | static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | 851 | static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) |
852 | { | 852 | { |
853 | struct msp_state *state; | 853 | struct msp_state *state; |
854 | struct v4l2_subdev *sd; | 854 | struct v4l2_subdev *sd; |
855 | int (*thread_func)(void *data) = NULL; | 855 | int (*thread_func)(void *data) = NULL; |
856 | int msp_hard; | 856 | int msp_hard; |
857 | int msp_family; | 857 | int msp_family; |
858 | int msp_revision; | 858 | int msp_revision; |
859 | int msp_product, msp_prod_hi, msp_prod_lo; | 859 | int msp_product, msp_prod_hi, msp_prod_lo; |
860 | int msp_rom; | 860 | int msp_rom; |
861 | 861 | ||
862 | if (!id) | 862 | if (!id) |
863 | strlcpy(client->name, "msp3400", sizeof(client->name)); | 863 | strlcpy(client->name, "msp3400", sizeof(client->name)); |
864 | 864 | ||
865 | if (msp_reset(client) == -1) { | 865 | if (msp_reset(client) == -1) { |
866 | v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); | 866 | v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); |
867 | return -ENODEV; | 867 | return -ENODEV; |
868 | } | 868 | } |
869 | 869 | ||
870 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 870 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
871 | if (!state) | 871 | if (!state) |
872 | return -ENOMEM; | 872 | return -ENOMEM; |
873 | 873 | ||
874 | sd = &state->sd; | 874 | sd = &state->sd; |
875 | v4l2_i2c_subdev_init(sd, client, &msp_ops); | 875 | v4l2_i2c_subdev_init(sd, client, &msp_ops); |
876 | 876 | ||
877 | state->v4l2_std = V4L2_STD_NTSC; | 877 | state->v4l2_std = V4L2_STD_NTSC; |
878 | state->audmode = V4L2_TUNER_MODE_STEREO; | 878 | state->audmode = V4L2_TUNER_MODE_STEREO; |
879 | state->volume = 58880; /* 0db gain */ | 879 | state->volume = 58880; /* 0db gain */ |
880 | state->balance = 32768; /* 0db gain */ | 880 | state->balance = 32768; /* 0db gain */ |
881 | state->bass = 32768; | 881 | state->bass = 32768; |
882 | state->treble = 32768; | 882 | state->treble = 32768; |
883 | state->loudness = 0; | 883 | state->loudness = 0; |
884 | state->input = -1; | 884 | state->input = -1; |
885 | state->muted = 0; | 885 | state->muted = 0; |
886 | state->i2s_mode = 0; | 886 | state->i2s_mode = 0; |
887 | init_waitqueue_head(&state->wq); | 887 | init_waitqueue_head(&state->wq); |
888 | /* These are the reset input/output positions */ | 888 | /* These are the reset input/output positions */ |
889 | state->routing.input = MSP_INPUT_DEFAULT; | 889 | state->routing.input = MSP_INPUT_DEFAULT; |
890 | state->routing.output = MSP_OUTPUT_DEFAULT; | 890 | state->routing.output = MSP_OUTPUT_DEFAULT; |
891 | 891 | ||
892 | state->rev1 = msp_read_dsp(client, 0x1e); | 892 | state->rev1 = msp_read_dsp(client, 0x1e); |
893 | if (state->rev1 != -1) | 893 | if (state->rev1 != -1) |
894 | state->rev2 = msp_read_dsp(client, 0x1f); | 894 | state->rev2 = msp_read_dsp(client, 0x1f); |
895 | v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", | 895 | v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", |
896 | state->rev1, state->rev2); | 896 | state->rev1, state->rev2); |
897 | if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { | 897 | if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { |
898 | v4l_dbg(1, msp_debug, client, | 898 | v4l_dbg(1, msp_debug, client, |
899 | "not an msp3400 (cannot read chip version)\n"); | 899 | "not an msp3400 (cannot read chip version)\n"); |
900 | kfree(state); | 900 | kfree(state); |
901 | return -ENODEV; | 901 | return -ENODEV; |
902 | } | 902 | } |
903 | 903 | ||
904 | msp_set_audio(client); | 904 | msp_set_audio(client); |
905 | 905 | ||
906 | msp_family = ((state->rev1 >> 4) & 0x0f) + 3; | 906 | msp_family = ((state->rev1 >> 4) & 0x0f) + 3; |
907 | msp_product = (state->rev2 >> 8) & 0xff; | 907 | msp_product = (state->rev2 >> 8) & 0xff; |
908 | msp_prod_hi = msp_product / 10; | 908 | msp_prod_hi = msp_product / 10; |
909 | msp_prod_lo = msp_product % 10; | 909 | msp_prod_lo = msp_product % 10; |
910 | msp_revision = (state->rev1 & 0x0f) + '@'; | 910 | msp_revision = (state->rev1 & 0x0f) + '@'; |
911 | msp_hard = ((state->rev1 >> 8) & 0xff) + '@'; | 911 | msp_hard = ((state->rev1 >> 8) & 0xff) + '@'; |
912 | msp_rom = state->rev2 & 0x1f; | 912 | msp_rom = state->rev2 & 0x1f; |
913 | /* Rev B=2, C=3, D=4, G=7 */ | 913 | /* Rev B=2, C=3, D=4, G=7 */ |
914 | state->ident = msp_family * 10000 + 4000 + msp_product * 10 + | 914 | state->ident = msp_family * 10000 + 4000 + msp_product * 10 + |
915 | msp_revision - '@'; | 915 | msp_revision - '@'; |
916 | 916 | ||
917 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ | 917 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ |
918 | state->has_nicam = | 918 | state->has_nicam = |
919 | msp_prod_hi == 1 || msp_prod_hi == 5; | 919 | msp_prod_hi == 1 || msp_prod_hi == 5; |
920 | /* Has radio support: was added with revision G */ | 920 | /* Has radio support: was added with revision G */ |
921 | state->has_radio = | 921 | state->has_radio = |
922 | msp_revision >= 'G'; | 922 | msp_revision >= 'G'; |
923 | /* Has headphones output: not for stripped down products */ | 923 | /* Has headphones output: not for stripped down products */ |
924 | state->has_headphones = | 924 | state->has_headphones = |
925 | msp_prod_lo < 5; | 925 | msp_prod_lo < 5; |
926 | /* Has scart2 input: not in stripped down products of the '3' family */ | 926 | /* Has scart2 input: not in stripped down products of the '3' family */ |
927 | state->has_scart2 = | 927 | state->has_scart2 = |
928 | msp_family >= 4 || msp_prod_lo < 7; | 928 | msp_family >= 4 || msp_prod_lo < 7; |
929 | /* Has scart3 input: not in stripped down products of the '3' family */ | 929 | /* Has scart3 input: not in stripped down products of the '3' family */ |
930 | state->has_scart3 = | 930 | state->has_scart3 = |
931 | msp_family >= 4 || msp_prod_lo < 5; | 931 | msp_family >= 4 || msp_prod_lo < 5; |
932 | /* Has scart4 input: not in pre D revisions, not in stripped D revs */ | 932 | /* Has scart4 input: not in pre D revisions, not in stripped D revs */ |
933 | state->has_scart4 = | 933 | state->has_scart4 = |
934 | msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); | 934 | msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); |
935 | /* Has scart2 output: not in stripped down products of | 935 | /* Has scart2 output: not in stripped down products of |
936 | * the '3' family */ | 936 | * the '3' family */ |
937 | state->has_scart2_out = | 937 | state->has_scart2_out = |
938 | msp_family >= 4 || msp_prod_lo < 5; | 938 | msp_family >= 4 || msp_prod_lo < 5; |
939 | /* Has scart2 a volume control? Not in pre-D revisions. */ | 939 | /* Has scart2 a volume control? Not in pre-D revisions. */ |
940 | state->has_scart2_out_volume = | 940 | state->has_scart2_out_volume = |
941 | msp_revision > 'C' && state->has_scart2_out; | 941 | msp_revision > 'C' && state->has_scart2_out; |
942 | /* Has a configurable i2s out? */ | 942 | /* Has a configurable i2s out? */ |
943 | state->has_i2s_conf = | 943 | state->has_i2s_conf = |
944 | msp_revision >= 'G' && msp_prod_lo < 7; | 944 | msp_revision >= 'G' && msp_prod_lo < 7; |
945 | /* Has subwoofer output: not in pre-D revs and not in stripped down | 945 | /* Has subwoofer output: not in pre-D revs and not in stripped down |
946 | * products */ | 946 | * products */ |
947 | state->has_subwoofer = | 947 | state->has_subwoofer = |
948 | msp_revision >= 'D' && msp_prod_lo < 5; | 948 | msp_revision >= 'D' && msp_prod_lo < 5; |
949 | /* Has soundprocessing (bass/treble/balance/loudness/equalizer): | 949 | /* Has soundprocessing (bass/treble/balance/loudness/equalizer): |
950 | * not in stripped down products */ | 950 | * not in stripped down products */ |
951 | state->has_sound_processing = | 951 | state->has_sound_processing = |
952 | msp_prod_lo < 7; | 952 | msp_prod_lo < 7; |
953 | /* Has Virtual Dolby Surround: only in msp34x1 */ | 953 | /* Has Virtual Dolby Surround: only in msp34x1 */ |
954 | state->has_virtual_dolby_surround = | 954 | state->has_virtual_dolby_surround = |
955 | msp_revision == 'G' && msp_prod_lo == 1; | 955 | msp_revision == 'G' && msp_prod_lo == 1; |
956 | /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ | 956 | /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ |
957 | state->has_dolby_pro_logic = | 957 | state->has_dolby_pro_logic = |
958 | msp_revision == 'G' && msp_prod_lo == 2; | 958 | msp_revision == 'G' && msp_prod_lo == 2; |
959 | /* The msp343xG supports BTSC only and cannot do Automatic Standard | 959 | /* The msp343xG supports BTSC only and cannot do Automatic Standard |
960 | * Detection. */ | 960 | * Detection. */ |
961 | state->force_btsc = | 961 | state->force_btsc = |
962 | msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; | 962 | msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; |
963 | 963 | ||
964 | state->opmode = opmode; | 964 | state->opmode = opmode; |
965 | if (state->opmode == OPMODE_AUTO) { | 965 | if (state->opmode == OPMODE_AUTO) { |
966 | /* MSP revision G and up have both autodetect and autoselect */ | 966 | /* MSP revision G and up have both autodetect and autoselect */ |
967 | if (msp_revision >= 'G') | 967 | if (msp_revision >= 'G') |
968 | state->opmode = OPMODE_AUTOSELECT; | 968 | state->opmode = OPMODE_AUTOSELECT; |
969 | /* MSP revision D and up have autodetect */ | 969 | /* MSP revision D and up have autodetect */ |
970 | else if (msp_revision >= 'D') | 970 | else if (msp_revision >= 'D') |
971 | state->opmode = OPMODE_AUTODETECT; | 971 | state->opmode = OPMODE_AUTODETECT; |
972 | else | 972 | else |
973 | state->opmode = OPMODE_MANUAL; | 973 | state->opmode = OPMODE_MANUAL; |
974 | } | 974 | } |
975 | 975 | ||
976 | /* hello world :-) */ | 976 | /* hello world :-) */ |
977 | v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", | 977 | v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", |
978 | msp_family, msp_product, | 978 | msp_family, msp_product, |
979 | msp_revision, msp_hard, msp_rom, | 979 | msp_revision, msp_hard, msp_rom, |
980 | client->addr << 1, client->adapter->name); | 980 | client->addr << 1, client->adapter->name); |
981 | v4l_info(client, "%s ", client->name); | 981 | v4l_info(client, "%s ", client->name); |
982 | if (state->has_nicam && state->has_radio) | 982 | if (state->has_nicam && state->has_radio) |
983 | printk(KERN_CONT "supports nicam and radio, "); | 983 | printk(KERN_CONT "supports nicam and radio, "); |
984 | else if (state->has_nicam) | 984 | else if (state->has_nicam) |
985 | printk(KERN_CONT "supports nicam, "); | 985 | printk(KERN_CONT "supports nicam, "); |
986 | else if (state->has_radio) | 986 | else if (state->has_radio) |
987 | printk(KERN_CONT "supports radio, "); | 987 | printk(KERN_CONT "supports radio, "); |
988 | printk(KERN_CONT "mode is "); | 988 | printk(KERN_CONT "mode is "); |
989 | 989 | ||
990 | /* version-specific initialization */ | 990 | /* version-specific initialization */ |
991 | switch (state->opmode) { | 991 | switch (state->opmode) { |
992 | case OPMODE_MANUAL: | 992 | case OPMODE_MANUAL: |
993 | printk(KERN_CONT "manual"); | 993 | printk(KERN_CONT "manual"); |
994 | thread_func = msp3400c_thread; | 994 | thread_func = msp3400c_thread; |
995 | break; | 995 | break; |
996 | case OPMODE_AUTODETECT: | 996 | case OPMODE_AUTODETECT: |
997 | printk(KERN_CONT "autodetect"); | 997 | printk(KERN_CONT "autodetect"); |
998 | thread_func = msp3410d_thread; | 998 | thread_func = msp3410d_thread; |
999 | break; | 999 | break; |
1000 | case OPMODE_AUTOSELECT: | 1000 | case OPMODE_AUTOSELECT: |
1001 | printk(KERN_CONT "autodetect and autoselect"); | 1001 | printk(KERN_CONT "autodetect and autoselect"); |
1002 | thread_func = msp34xxg_thread; | 1002 | thread_func = msp34xxg_thread; |
1003 | break; | 1003 | break; |
1004 | } | 1004 | } |
1005 | printk(KERN_CONT "\n"); | 1005 | printk(KERN_CONT "\n"); |
1006 | 1006 | ||
1007 | /* startup control thread if needed */ | 1007 | /* startup control thread if needed */ |
1008 | if (thread_func) { | 1008 | if (thread_func) { |
1009 | state->kthread = kthread_run(thread_func, client, "msp34xx"); | 1009 | state->kthread = kthread_run(thread_func, client, "msp34xx"); |
1010 | 1010 | ||
1011 | if (IS_ERR(state->kthread)) | 1011 | if (IS_ERR(state->kthread)) |
1012 | v4l_warn(client, "kernel_thread() failed\n"); | 1012 | v4l_warn(client, "kernel_thread() failed\n"); |
1013 | msp_wake_thread(client); | 1013 | msp_wake_thread(client); |
1014 | } | 1014 | } |
1015 | return 0; | 1015 | return 0; |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static int msp_remove(struct i2c_client *client) | 1018 | static int msp_remove(struct i2c_client *client) |
1019 | { | 1019 | { |
1020 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | 1020 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
1021 | 1021 | ||
1022 | v4l2_device_unregister_subdev(&state->sd); | 1022 | v4l2_device_unregister_subdev(&state->sd); |
1023 | /* shutdown control thread */ | 1023 | /* shutdown control thread */ |
1024 | if (state->kthread) { | 1024 | if (state->kthread) { |
1025 | state->restart = 1; | 1025 | state->restart = 1; |
1026 | kthread_stop(state->kthread); | 1026 | kthread_stop(state->kthread); |
1027 | } | 1027 | } |
1028 | msp_reset(client); | 1028 | msp_reset(client); |
1029 | 1029 | ||
1030 | kfree(state); | 1030 | kfree(state); |
1031 | return 0; | 1031 | return 0; |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | /* ----------------------------------------------------------------------- */ | 1034 | /* ----------------------------------------------------------------------- */ |
1035 | 1035 | ||
1036 | static const struct i2c_device_id msp_id[] = { | 1036 | static const struct i2c_device_id msp_id[] = { |
1037 | { "msp3400", 0 }, | 1037 | { "msp3400", 0 }, |
1038 | { } | 1038 | { } |
1039 | }; | 1039 | }; |
1040 | MODULE_DEVICE_TABLE(i2c, msp_id); | 1040 | MODULE_DEVICE_TABLE(i2c, msp_id); |
1041 | 1041 | ||
1042 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { | 1042 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { |
1043 | .name = "msp3400", | 1043 | .name = "msp3400", |
1044 | .driverid = I2C_DRIVERID_MSP3400, | 1044 | .driverid = I2C_DRIVERID_MSP3400, |
1045 | .command = msp_command, | 1045 | .command = msp_command, |
1046 | .probe = msp_probe, | 1046 | .probe = msp_probe, |
1047 | .remove = msp_remove, | 1047 | .remove = msp_remove, |
1048 | .suspend = msp_suspend, | 1048 | .suspend = msp_suspend, |
1049 | .resume = msp_resume, | 1049 | .resume = msp_resume, |
1050 | .id_table = msp_id, | 1050 | .id_table = msp_id, |
1051 | }; | 1051 | }; |
1052 | 1052 | ||
1053 | /* | 1053 | /* |
1054 | * Overrides for Emacs so that we follow Linus's tabbing style. | 1054 | * Overrides for Emacs so that we follow Linus's tabbing style. |
1055 | * --------------------------------------------------------------------------- | 1055 | * --------------------------------------------------------------------------- |
1056 | * Local variables: | 1056 | * Local variables: |
1057 | * c-basic-offset: 8 | 1057 | * c-basic-offset: 8 |
1058 | * End: | 1058 | * End: |
1059 | */ | 1059 | */ |
1060 | 1060 |
drivers/media/video/ov7670.c
1 | /* | 1 | /* |
2 | * A V4L2 driver for OmniVision OV7670 cameras. | 2 | * A V4L2 driver for OmniVision OV7670 cameras. |
3 | * | 3 | * |
4 | * Copyright 2006 One Laptop Per Child Association, Inc. Written | 4 | * Copyright 2006 One Laptop Per Child Association, Inc. Written |
5 | * by Jonathan Corbet with substantial inspiration from Mark | 5 | * by Jonathan Corbet with substantial inspiration from Mark |
6 | * McClelland's ovcamchip code. | 6 | * McClelland's ovcamchip code. |
7 | * | 7 | * |
8 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | 8 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> |
9 | * | 9 | * |
10 | * This file may be distributed under the terms of the GNU General | 10 | * This file may be distributed under the terms of the GNU General |
11 | * Public License, version 2. | 11 | * Public License, version 2. |
12 | */ | 12 | */ |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/videodev.h> | 17 | #include <linux/videodev2.h> |
18 | #include <media/v4l2-common.h> | 18 | #include <media/v4l2-common.h> |
19 | #include <media/v4l2-chip-ident.h> | 19 | #include <media/v4l2-chip-ident.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | 21 | ||
22 | 22 | ||
23 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 23 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
24 | MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); | 24 | MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); |
25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Basic window sizes. These probably belong somewhere more globally | 28 | * Basic window sizes. These probably belong somewhere more globally |
29 | * useful. | 29 | * useful. |
30 | */ | 30 | */ |
31 | #define VGA_WIDTH 640 | 31 | #define VGA_WIDTH 640 |
32 | #define VGA_HEIGHT 480 | 32 | #define VGA_HEIGHT 480 |
33 | #define QVGA_WIDTH 320 | 33 | #define QVGA_WIDTH 320 |
34 | #define QVGA_HEIGHT 240 | 34 | #define QVGA_HEIGHT 240 |
35 | #define CIF_WIDTH 352 | 35 | #define CIF_WIDTH 352 |
36 | #define CIF_HEIGHT 288 | 36 | #define CIF_HEIGHT 288 |
37 | #define QCIF_WIDTH 176 | 37 | #define QCIF_WIDTH 176 |
38 | #define QCIF_HEIGHT 144 | 38 | #define QCIF_HEIGHT 144 |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Our nominal (default) frame rate. | 41 | * Our nominal (default) frame rate. |
42 | */ | 42 | */ |
43 | #define OV7670_FRAME_RATE 30 | 43 | #define OV7670_FRAME_RATE 30 |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * The 7670 sits on i2c with ID 0x42 | 46 | * The 7670 sits on i2c with ID 0x42 |
47 | */ | 47 | */ |
48 | #define OV7670_I2C_ADDR 0x42 | 48 | #define OV7670_I2C_ADDR 0x42 |
49 | 49 | ||
50 | /* Registers */ | 50 | /* Registers */ |
51 | #define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ | 51 | #define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ |
52 | #define REG_BLUE 0x01 /* blue gain */ | 52 | #define REG_BLUE 0x01 /* blue gain */ |
53 | #define REG_RED 0x02 /* red gain */ | 53 | #define REG_RED 0x02 /* red gain */ |
54 | #define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ | 54 | #define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ |
55 | #define REG_COM1 0x04 /* Control 1 */ | 55 | #define REG_COM1 0x04 /* Control 1 */ |
56 | #define COM1_CCIR656 0x40 /* CCIR656 enable */ | 56 | #define COM1_CCIR656 0x40 /* CCIR656 enable */ |
57 | #define REG_BAVE 0x05 /* U/B Average level */ | 57 | #define REG_BAVE 0x05 /* U/B Average level */ |
58 | #define REG_GbAVE 0x06 /* Y/Gb Average level */ | 58 | #define REG_GbAVE 0x06 /* Y/Gb Average level */ |
59 | #define REG_AECHH 0x07 /* AEC MS 5 bits */ | 59 | #define REG_AECHH 0x07 /* AEC MS 5 bits */ |
60 | #define REG_RAVE 0x08 /* V/R Average level */ | 60 | #define REG_RAVE 0x08 /* V/R Average level */ |
61 | #define REG_COM2 0x09 /* Control 2 */ | 61 | #define REG_COM2 0x09 /* Control 2 */ |
62 | #define COM2_SSLEEP 0x10 /* Soft sleep mode */ | 62 | #define COM2_SSLEEP 0x10 /* Soft sleep mode */ |
63 | #define REG_PID 0x0a /* Product ID MSB */ | 63 | #define REG_PID 0x0a /* Product ID MSB */ |
64 | #define REG_VER 0x0b /* Product ID LSB */ | 64 | #define REG_VER 0x0b /* Product ID LSB */ |
65 | #define REG_COM3 0x0c /* Control 3 */ | 65 | #define REG_COM3 0x0c /* Control 3 */ |
66 | #define COM3_SWAP 0x40 /* Byte swap */ | 66 | #define COM3_SWAP 0x40 /* Byte swap */ |
67 | #define COM3_SCALEEN 0x08 /* Enable scaling */ | 67 | #define COM3_SCALEEN 0x08 /* Enable scaling */ |
68 | #define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ | 68 | #define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ |
69 | #define REG_COM4 0x0d /* Control 4 */ | 69 | #define REG_COM4 0x0d /* Control 4 */ |
70 | #define REG_COM5 0x0e /* All "reserved" */ | 70 | #define REG_COM5 0x0e /* All "reserved" */ |
71 | #define REG_COM6 0x0f /* Control 6 */ | 71 | #define REG_COM6 0x0f /* Control 6 */ |
72 | #define REG_AECH 0x10 /* More bits of AEC value */ | 72 | #define REG_AECH 0x10 /* More bits of AEC value */ |
73 | #define REG_CLKRC 0x11 /* Clocl control */ | 73 | #define REG_CLKRC 0x11 /* Clocl control */ |
74 | #define CLK_EXT 0x40 /* Use external clock directly */ | 74 | #define CLK_EXT 0x40 /* Use external clock directly */ |
75 | #define CLK_SCALE 0x3f /* Mask for internal clock scale */ | 75 | #define CLK_SCALE 0x3f /* Mask for internal clock scale */ |
76 | #define REG_COM7 0x12 /* Control 7 */ | 76 | #define REG_COM7 0x12 /* Control 7 */ |
77 | #define COM7_RESET 0x80 /* Register reset */ | 77 | #define COM7_RESET 0x80 /* Register reset */ |
78 | #define COM7_FMT_MASK 0x38 | 78 | #define COM7_FMT_MASK 0x38 |
79 | #define COM7_FMT_VGA 0x00 | 79 | #define COM7_FMT_VGA 0x00 |
80 | #define COM7_FMT_CIF 0x20 /* CIF format */ | 80 | #define COM7_FMT_CIF 0x20 /* CIF format */ |
81 | #define COM7_FMT_QVGA 0x10 /* QVGA format */ | 81 | #define COM7_FMT_QVGA 0x10 /* QVGA format */ |
82 | #define COM7_FMT_QCIF 0x08 /* QCIF format */ | 82 | #define COM7_FMT_QCIF 0x08 /* QCIF format */ |
83 | #define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ | 83 | #define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ |
84 | #define COM7_YUV 0x00 /* YUV */ | 84 | #define COM7_YUV 0x00 /* YUV */ |
85 | #define COM7_BAYER 0x01 /* Bayer format */ | 85 | #define COM7_BAYER 0x01 /* Bayer format */ |
86 | #define COM7_PBAYER 0x05 /* "Processed bayer" */ | 86 | #define COM7_PBAYER 0x05 /* "Processed bayer" */ |
87 | #define REG_COM8 0x13 /* Control 8 */ | 87 | #define REG_COM8 0x13 /* Control 8 */ |
88 | #define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ | 88 | #define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ |
89 | #define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ | 89 | #define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ |
90 | #define COM8_BFILT 0x20 /* Band filter enable */ | 90 | #define COM8_BFILT 0x20 /* Band filter enable */ |
91 | #define COM8_AGC 0x04 /* Auto gain enable */ | 91 | #define COM8_AGC 0x04 /* Auto gain enable */ |
92 | #define COM8_AWB 0x02 /* White balance enable */ | 92 | #define COM8_AWB 0x02 /* White balance enable */ |
93 | #define COM8_AEC 0x01 /* Auto exposure enable */ | 93 | #define COM8_AEC 0x01 /* Auto exposure enable */ |
94 | #define REG_COM9 0x14 /* Control 9 - gain ceiling */ | 94 | #define REG_COM9 0x14 /* Control 9 - gain ceiling */ |
95 | #define REG_COM10 0x15 /* Control 10 */ | 95 | #define REG_COM10 0x15 /* Control 10 */ |
96 | #define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ | 96 | #define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ |
97 | #define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ | 97 | #define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ |
98 | #define COM10_HREF_REV 0x08 /* Reverse HREF */ | 98 | #define COM10_HREF_REV 0x08 /* Reverse HREF */ |
99 | #define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ | 99 | #define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ |
100 | #define COM10_VS_NEG 0x02 /* VSYNC negative */ | 100 | #define COM10_VS_NEG 0x02 /* VSYNC negative */ |
101 | #define COM10_HS_NEG 0x01 /* HSYNC negative */ | 101 | #define COM10_HS_NEG 0x01 /* HSYNC negative */ |
102 | #define REG_HSTART 0x17 /* Horiz start high bits */ | 102 | #define REG_HSTART 0x17 /* Horiz start high bits */ |
103 | #define REG_HSTOP 0x18 /* Horiz stop high bits */ | 103 | #define REG_HSTOP 0x18 /* Horiz stop high bits */ |
104 | #define REG_VSTART 0x19 /* Vert start high bits */ | 104 | #define REG_VSTART 0x19 /* Vert start high bits */ |
105 | #define REG_VSTOP 0x1a /* Vert stop high bits */ | 105 | #define REG_VSTOP 0x1a /* Vert stop high bits */ |
106 | #define REG_PSHFT 0x1b /* Pixel delay after HREF */ | 106 | #define REG_PSHFT 0x1b /* Pixel delay after HREF */ |
107 | #define REG_MIDH 0x1c /* Manuf. ID high */ | 107 | #define REG_MIDH 0x1c /* Manuf. ID high */ |
108 | #define REG_MIDL 0x1d /* Manuf. ID low */ | 108 | #define REG_MIDL 0x1d /* Manuf. ID low */ |
109 | #define REG_MVFP 0x1e /* Mirror / vflip */ | 109 | #define REG_MVFP 0x1e /* Mirror / vflip */ |
110 | #define MVFP_MIRROR 0x20 /* Mirror image */ | 110 | #define MVFP_MIRROR 0x20 /* Mirror image */ |
111 | #define MVFP_FLIP 0x10 /* Vertical flip */ | 111 | #define MVFP_FLIP 0x10 /* Vertical flip */ |
112 | 112 | ||
113 | #define REG_AEW 0x24 /* AGC upper limit */ | 113 | #define REG_AEW 0x24 /* AGC upper limit */ |
114 | #define REG_AEB 0x25 /* AGC lower limit */ | 114 | #define REG_AEB 0x25 /* AGC lower limit */ |
115 | #define REG_VPT 0x26 /* AGC/AEC fast mode op region */ | 115 | #define REG_VPT 0x26 /* AGC/AEC fast mode op region */ |
116 | #define REG_HSYST 0x30 /* HSYNC rising edge delay */ | 116 | #define REG_HSYST 0x30 /* HSYNC rising edge delay */ |
117 | #define REG_HSYEN 0x31 /* HSYNC falling edge delay */ | 117 | #define REG_HSYEN 0x31 /* HSYNC falling edge delay */ |
118 | #define REG_HREF 0x32 /* HREF pieces */ | 118 | #define REG_HREF 0x32 /* HREF pieces */ |
119 | #define REG_TSLB 0x3a /* lots of stuff */ | 119 | #define REG_TSLB 0x3a /* lots of stuff */ |
120 | #define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ | 120 | #define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ |
121 | #define REG_COM11 0x3b /* Control 11 */ | 121 | #define REG_COM11 0x3b /* Control 11 */ |
122 | #define COM11_NIGHT 0x80 /* NIght mode enable */ | 122 | #define COM11_NIGHT 0x80 /* NIght mode enable */ |
123 | #define COM11_NMFR 0x60 /* Two bit NM frame rate */ | 123 | #define COM11_NMFR 0x60 /* Two bit NM frame rate */ |
124 | #define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ | 124 | #define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ |
125 | #define COM11_50HZ 0x08 /* Manual 50Hz select */ | 125 | #define COM11_50HZ 0x08 /* Manual 50Hz select */ |
126 | #define COM11_EXP 0x02 | 126 | #define COM11_EXP 0x02 |
127 | #define REG_COM12 0x3c /* Control 12 */ | 127 | #define REG_COM12 0x3c /* Control 12 */ |
128 | #define COM12_HREF 0x80 /* HREF always */ | 128 | #define COM12_HREF 0x80 /* HREF always */ |
129 | #define REG_COM13 0x3d /* Control 13 */ | 129 | #define REG_COM13 0x3d /* Control 13 */ |
130 | #define COM13_GAMMA 0x80 /* Gamma enable */ | 130 | #define COM13_GAMMA 0x80 /* Gamma enable */ |
131 | #define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ | 131 | #define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ |
132 | #define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ | 132 | #define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ |
133 | #define REG_COM14 0x3e /* Control 14 */ | 133 | #define REG_COM14 0x3e /* Control 14 */ |
134 | #define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ | 134 | #define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ |
135 | #define REG_EDGE 0x3f /* Edge enhancement factor */ | 135 | #define REG_EDGE 0x3f /* Edge enhancement factor */ |
136 | #define REG_COM15 0x40 /* Control 15 */ | 136 | #define REG_COM15 0x40 /* Control 15 */ |
137 | #define COM15_R10F0 0x00 /* Data range 10 to F0 */ | 137 | #define COM15_R10F0 0x00 /* Data range 10 to F0 */ |
138 | #define COM15_R01FE 0x80 /* 01 to FE */ | 138 | #define COM15_R01FE 0x80 /* 01 to FE */ |
139 | #define COM15_R00FF 0xc0 /* 00 to FF */ | 139 | #define COM15_R00FF 0xc0 /* 00 to FF */ |
140 | #define COM15_RGB565 0x10 /* RGB565 output */ | 140 | #define COM15_RGB565 0x10 /* RGB565 output */ |
141 | #define COM15_RGB555 0x30 /* RGB555 output */ | 141 | #define COM15_RGB555 0x30 /* RGB555 output */ |
142 | #define REG_COM16 0x41 /* Control 16 */ | 142 | #define REG_COM16 0x41 /* Control 16 */ |
143 | #define COM16_AWBGAIN 0x08 /* AWB gain enable */ | 143 | #define COM16_AWBGAIN 0x08 /* AWB gain enable */ |
144 | #define REG_COM17 0x42 /* Control 17 */ | 144 | #define REG_COM17 0x42 /* Control 17 */ |
145 | #define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ | 145 | #define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ |
146 | #define COM17_CBAR 0x08 /* DSP Color bar */ | 146 | #define COM17_CBAR 0x08 /* DSP Color bar */ |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * This matrix defines how the colors are generated, must be | 149 | * This matrix defines how the colors are generated, must be |
150 | * tweaked to adjust hue and saturation. | 150 | * tweaked to adjust hue and saturation. |
151 | * | 151 | * |
152 | * Order: v-red, v-green, v-blue, u-red, u-green, u-blue | 152 | * Order: v-red, v-green, v-blue, u-red, u-green, u-blue |
153 | * | 153 | * |
154 | * They are nine-bit signed quantities, with the sign bit | 154 | * They are nine-bit signed quantities, with the sign bit |
155 | * stored in 0x58. Sign for v-red is bit 0, and up from there. | 155 | * stored in 0x58. Sign for v-red is bit 0, and up from there. |
156 | */ | 156 | */ |
157 | #define REG_CMATRIX_BASE 0x4f | 157 | #define REG_CMATRIX_BASE 0x4f |
158 | #define CMATRIX_LEN 6 | 158 | #define CMATRIX_LEN 6 |
159 | #define REG_CMATRIX_SIGN 0x58 | 159 | #define REG_CMATRIX_SIGN 0x58 |
160 | 160 | ||
161 | 161 | ||
162 | #define REG_BRIGHT 0x55 /* Brightness */ | 162 | #define REG_BRIGHT 0x55 /* Brightness */ |
163 | #define REG_CONTRAS 0x56 /* Contrast control */ | 163 | #define REG_CONTRAS 0x56 /* Contrast control */ |
164 | 164 | ||
165 | #define REG_GFIX 0x69 /* Fix gain control */ | 165 | #define REG_GFIX 0x69 /* Fix gain control */ |
166 | 166 | ||
167 | #define REG_REG76 0x76 /* OV's name */ | 167 | #define REG_REG76 0x76 /* OV's name */ |
168 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ | 168 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ |
169 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ | 169 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ |
170 | 170 | ||
171 | #define REG_RGB444 0x8c /* RGB 444 control */ | 171 | #define REG_RGB444 0x8c /* RGB 444 control */ |
172 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ | 172 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ |
173 | #define R444_RGBX 0x01 /* Empty nibble at end */ | 173 | #define R444_RGBX 0x01 /* Empty nibble at end */ |
174 | 174 | ||
175 | #define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ | 175 | #define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ |
176 | #define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ | 176 | #define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ |
177 | 177 | ||
178 | #define REG_BD50MAX 0xa5 /* 50hz banding step limit */ | 178 | #define REG_BD50MAX 0xa5 /* 50hz banding step limit */ |
179 | #define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ | 179 | #define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ |
180 | #define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ | 180 | #define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ |
181 | #define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ | 181 | #define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ |
182 | #define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ | 182 | #define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ |
183 | #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ | 183 | #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ |
184 | #define REG_BD60MAX 0xab /* 60hz banding step limit */ | 184 | #define REG_BD60MAX 0xab /* 60hz banding step limit */ |
185 | 185 | ||
186 | 186 | ||
187 | /* | 187 | /* |
188 | * Information we maintain about a known sensor. | 188 | * Information we maintain about a known sensor. |
189 | */ | 189 | */ |
190 | struct ov7670_format_struct; /* coming later */ | 190 | struct ov7670_format_struct; /* coming later */ |
191 | struct ov7670_info { | 191 | struct ov7670_info { |
192 | struct ov7670_format_struct *fmt; /* Current format */ | 192 | struct ov7670_format_struct *fmt; /* Current format */ |
193 | unsigned char sat; /* Saturation value */ | 193 | unsigned char sat; /* Saturation value */ |
194 | int hue; /* Hue value */ | 194 | int hue; /* Hue value */ |
195 | }; | 195 | }; |
196 | 196 | ||
197 | 197 | ||
198 | 198 | ||
199 | 199 | ||
200 | /* | 200 | /* |
201 | * The default register settings, as obtained from OmniVision. There | 201 | * The default register settings, as obtained from OmniVision. There |
202 | * is really no making sense of most of these - lots of "reserved" values | 202 | * is really no making sense of most of these - lots of "reserved" values |
203 | * and such. | 203 | * and such. |
204 | * | 204 | * |
205 | * These settings give VGA YUYV. | 205 | * These settings give VGA YUYV. |
206 | */ | 206 | */ |
207 | 207 | ||
208 | struct regval_list { | 208 | struct regval_list { |
209 | unsigned char reg_num; | 209 | unsigned char reg_num; |
210 | unsigned char value; | 210 | unsigned char value; |
211 | }; | 211 | }; |
212 | 212 | ||
213 | static struct regval_list ov7670_default_regs[] = { | 213 | static struct regval_list ov7670_default_regs[] = { |
214 | { REG_COM7, COM7_RESET }, | 214 | { REG_COM7, COM7_RESET }, |
215 | /* | 215 | /* |
216 | * Clock scale: 3 = 15fps | 216 | * Clock scale: 3 = 15fps |
217 | * 2 = 20fps | 217 | * 2 = 20fps |
218 | * 1 = 30fps | 218 | * 1 = 30fps |
219 | */ | 219 | */ |
220 | { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */ | 220 | { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */ |
221 | { REG_TSLB, 0x04 }, /* OV */ | 221 | { REG_TSLB, 0x04 }, /* OV */ |
222 | { REG_COM7, 0 }, /* VGA */ | 222 | { REG_COM7, 0 }, /* VGA */ |
223 | /* | 223 | /* |
224 | * Set the hardware window. These values from OV don't entirely | 224 | * Set the hardware window. These values from OV don't entirely |
225 | * make sense - hstop is less than hstart. But they work... | 225 | * make sense - hstop is less than hstart. But they work... |
226 | */ | 226 | */ |
227 | { REG_HSTART, 0x13 }, { REG_HSTOP, 0x01 }, | 227 | { REG_HSTART, 0x13 }, { REG_HSTOP, 0x01 }, |
228 | { REG_HREF, 0xb6 }, { REG_VSTART, 0x02 }, | 228 | { REG_HREF, 0xb6 }, { REG_VSTART, 0x02 }, |
229 | { REG_VSTOP, 0x7a }, { REG_VREF, 0x0a }, | 229 | { REG_VSTOP, 0x7a }, { REG_VREF, 0x0a }, |
230 | 230 | ||
231 | { REG_COM3, 0 }, { REG_COM14, 0 }, | 231 | { REG_COM3, 0 }, { REG_COM14, 0 }, |
232 | /* Mystery scaling numbers */ | 232 | /* Mystery scaling numbers */ |
233 | { 0x70, 0x3a }, { 0x71, 0x35 }, | 233 | { 0x70, 0x3a }, { 0x71, 0x35 }, |
234 | { 0x72, 0x11 }, { 0x73, 0xf0 }, | 234 | { 0x72, 0x11 }, { 0x73, 0xf0 }, |
235 | { 0xa2, 0x02 }, { REG_COM10, 0x0 }, | 235 | { 0xa2, 0x02 }, { REG_COM10, 0x0 }, |
236 | 236 | ||
237 | /* Gamma curve values */ | 237 | /* Gamma curve values */ |
238 | { 0x7a, 0x20 }, { 0x7b, 0x10 }, | 238 | { 0x7a, 0x20 }, { 0x7b, 0x10 }, |
239 | { 0x7c, 0x1e }, { 0x7d, 0x35 }, | 239 | { 0x7c, 0x1e }, { 0x7d, 0x35 }, |
240 | { 0x7e, 0x5a }, { 0x7f, 0x69 }, | 240 | { 0x7e, 0x5a }, { 0x7f, 0x69 }, |
241 | { 0x80, 0x76 }, { 0x81, 0x80 }, | 241 | { 0x80, 0x76 }, { 0x81, 0x80 }, |
242 | { 0x82, 0x88 }, { 0x83, 0x8f }, | 242 | { 0x82, 0x88 }, { 0x83, 0x8f }, |
243 | { 0x84, 0x96 }, { 0x85, 0xa3 }, | 243 | { 0x84, 0x96 }, { 0x85, 0xa3 }, |
244 | { 0x86, 0xaf }, { 0x87, 0xc4 }, | 244 | { 0x86, 0xaf }, { 0x87, 0xc4 }, |
245 | { 0x88, 0xd7 }, { 0x89, 0xe8 }, | 245 | { 0x88, 0xd7 }, { 0x89, 0xe8 }, |
246 | 246 | ||
247 | /* AGC and AEC parameters. Note we start by disabling those features, | 247 | /* AGC and AEC parameters. Note we start by disabling those features, |
248 | then turn them only after tweaking the values. */ | 248 | then turn them only after tweaking the values. */ |
249 | { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT }, | 249 | { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT }, |
250 | { REG_GAIN, 0 }, { REG_AECH, 0 }, | 250 | { REG_GAIN, 0 }, { REG_AECH, 0 }, |
251 | { REG_COM4, 0x40 }, /* magic reserved bit */ | 251 | { REG_COM4, 0x40 }, /* magic reserved bit */ |
252 | { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ | 252 | { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ |
253 | { REG_BD50MAX, 0x05 }, { REG_BD60MAX, 0x07 }, | 253 | { REG_BD50MAX, 0x05 }, { REG_BD60MAX, 0x07 }, |
254 | { REG_AEW, 0x95 }, { REG_AEB, 0x33 }, | 254 | { REG_AEW, 0x95 }, { REG_AEB, 0x33 }, |
255 | { REG_VPT, 0xe3 }, { REG_HAECC1, 0x78 }, | 255 | { REG_VPT, 0xe3 }, { REG_HAECC1, 0x78 }, |
256 | { REG_HAECC2, 0x68 }, { 0xa1, 0x03 }, /* magic */ | 256 | { REG_HAECC2, 0x68 }, { 0xa1, 0x03 }, /* magic */ |
257 | { REG_HAECC3, 0xd8 }, { REG_HAECC4, 0xd8 }, | 257 | { REG_HAECC3, 0xd8 }, { REG_HAECC4, 0xd8 }, |
258 | { REG_HAECC5, 0xf0 }, { REG_HAECC6, 0x90 }, | 258 | { REG_HAECC5, 0xf0 }, { REG_HAECC6, 0x90 }, |
259 | { REG_HAECC7, 0x94 }, | 259 | { REG_HAECC7, 0x94 }, |
260 | { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC }, | 260 | { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC }, |
261 | 261 | ||
262 | /* Almost all of these are magic "reserved" values. */ | 262 | /* Almost all of these are magic "reserved" values. */ |
263 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, | 263 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, |
264 | { 0x16, 0x02 }, { REG_MVFP, 0x07 }, | 264 | { 0x16, 0x02 }, { REG_MVFP, 0x07 }, |
265 | { 0x21, 0x02 }, { 0x22, 0x91 }, | 265 | { 0x21, 0x02 }, { 0x22, 0x91 }, |
266 | { 0x29, 0x07 }, { 0x33, 0x0b }, | 266 | { 0x29, 0x07 }, { 0x33, 0x0b }, |
267 | { 0x35, 0x0b }, { 0x37, 0x1d }, | 267 | { 0x35, 0x0b }, { 0x37, 0x1d }, |
268 | { 0x38, 0x71 }, { 0x39, 0x2a }, | 268 | { 0x38, 0x71 }, { 0x39, 0x2a }, |
269 | { REG_COM12, 0x78 }, { 0x4d, 0x40 }, | 269 | { REG_COM12, 0x78 }, { 0x4d, 0x40 }, |
270 | { 0x4e, 0x20 }, { REG_GFIX, 0 }, | 270 | { 0x4e, 0x20 }, { REG_GFIX, 0 }, |
271 | { 0x6b, 0x4a }, { 0x74, 0x10 }, | 271 | { 0x6b, 0x4a }, { 0x74, 0x10 }, |
272 | { 0x8d, 0x4f }, { 0x8e, 0 }, | 272 | { 0x8d, 0x4f }, { 0x8e, 0 }, |
273 | { 0x8f, 0 }, { 0x90, 0 }, | 273 | { 0x8f, 0 }, { 0x90, 0 }, |
274 | { 0x91, 0 }, { 0x96, 0 }, | 274 | { 0x91, 0 }, { 0x96, 0 }, |
275 | { 0x9a, 0 }, { 0xb0, 0x84 }, | 275 | { 0x9a, 0 }, { 0xb0, 0x84 }, |
276 | { 0xb1, 0x0c }, { 0xb2, 0x0e }, | 276 | { 0xb1, 0x0c }, { 0xb2, 0x0e }, |
277 | { 0xb3, 0x82 }, { 0xb8, 0x0a }, | 277 | { 0xb3, 0x82 }, { 0xb8, 0x0a }, |
278 | 278 | ||
279 | /* More reserved magic, some of which tweaks white balance */ | 279 | /* More reserved magic, some of which tweaks white balance */ |
280 | { 0x43, 0x0a }, { 0x44, 0xf0 }, | 280 | { 0x43, 0x0a }, { 0x44, 0xf0 }, |
281 | { 0x45, 0x34 }, { 0x46, 0x58 }, | 281 | { 0x45, 0x34 }, { 0x46, 0x58 }, |
282 | { 0x47, 0x28 }, { 0x48, 0x3a }, | 282 | { 0x47, 0x28 }, { 0x48, 0x3a }, |
283 | { 0x59, 0x88 }, { 0x5a, 0x88 }, | 283 | { 0x59, 0x88 }, { 0x5a, 0x88 }, |
284 | { 0x5b, 0x44 }, { 0x5c, 0x67 }, | 284 | { 0x5b, 0x44 }, { 0x5c, 0x67 }, |
285 | { 0x5d, 0x49 }, { 0x5e, 0x0e }, | 285 | { 0x5d, 0x49 }, { 0x5e, 0x0e }, |
286 | { 0x6c, 0x0a }, { 0x6d, 0x55 }, | 286 | { 0x6c, 0x0a }, { 0x6d, 0x55 }, |
287 | { 0x6e, 0x11 }, { 0x6f, 0x9f }, /* "9e for advance AWB" */ | 287 | { 0x6e, 0x11 }, { 0x6f, 0x9f }, /* "9e for advance AWB" */ |
288 | { 0x6a, 0x40 }, { REG_BLUE, 0x40 }, | 288 | { 0x6a, 0x40 }, { REG_BLUE, 0x40 }, |
289 | { REG_RED, 0x60 }, | 289 | { REG_RED, 0x60 }, |
290 | { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB }, | 290 | { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB }, |
291 | 291 | ||
292 | /* Matrix coefficients */ | 292 | /* Matrix coefficients */ |
293 | { 0x4f, 0x80 }, { 0x50, 0x80 }, | 293 | { 0x4f, 0x80 }, { 0x50, 0x80 }, |
294 | { 0x51, 0 }, { 0x52, 0x22 }, | 294 | { 0x51, 0 }, { 0x52, 0x22 }, |
295 | { 0x53, 0x5e }, { 0x54, 0x80 }, | 295 | { 0x53, 0x5e }, { 0x54, 0x80 }, |
296 | { 0x58, 0x9e }, | 296 | { 0x58, 0x9e }, |
297 | 297 | ||
298 | { REG_COM16, COM16_AWBGAIN }, { REG_EDGE, 0 }, | 298 | { REG_COM16, COM16_AWBGAIN }, { REG_EDGE, 0 }, |
299 | { 0x75, 0x05 }, { 0x76, 0xe1 }, | 299 | { 0x75, 0x05 }, { 0x76, 0xe1 }, |
300 | { 0x4c, 0 }, { 0x77, 0x01 }, | 300 | { 0x4c, 0 }, { 0x77, 0x01 }, |
301 | { REG_COM13, 0xc3 }, { 0x4b, 0x09 }, | 301 | { REG_COM13, 0xc3 }, { 0x4b, 0x09 }, |
302 | { 0xc9, 0x60 }, { REG_COM16, 0x38 }, | 302 | { 0xc9, 0x60 }, { REG_COM16, 0x38 }, |
303 | { 0x56, 0x40 }, | 303 | { 0x56, 0x40 }, |
304 | 304 | ||
305 | { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO }, | 305 | { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO }, |
306 | { 0xa4, 0x88 }, { 0x96, 0 }, | 306 | { 0xa4, 0x88 }, { 0x96, 0 }, |
307 | { 0x97, 0x30 }, { 0x98, 0x20 }, | 307 | { 0x97, 0x30 }, { 0x98, 0x20 }, |
308 | { 0x99, 0x30 }, { 0x9a, 0x84 }, | 308 | { 0x99, 0x30 }, { 0x9a, 0x84 }, |
309 | { 0x9b, 0x29 }, { 0x9c, 0x03 }, | 309 | { 0x9b, 0x29 }, { 0x9c, 0x03 }, |
310 | { 0x9d, 0x4c }, { 0x9e, 0x3f }, | 310 | { 0x9d, 0x4c }, { 0x9e, 0x3f }, |
311 | { 0x78, 0x04 }, | 311 | { 0x78, 0x04 }, |
312 | 312 | ||
313 | /* Extra-weird stuff. Some sort of multiplexor register */ | 313 | /* Extra-weird stuff. Some sort of multiplexor register */ |
314 | { 0x79, 0x01 }, { 0xc8, 0xf0 }, | 314 | { 0x79, 0x01 }, { 0xc8, 0xf0 }, |
315 | { 0x79, 0x0f }, { 0xc8, 0x00 }, | 315 | { 0x79, 0x0f }, { 0xc8, 0x00 }, |
316 | { 0x79, 0x10 }, { 0xc8, 0x7e }, | 316 | { 0x79, 0x10 }, { 0xc8, 0x7e }, |
317 | { 0x79, 0x0a }, { 0xc8, 0x80 }, | 317 | { 0x79, 0x0a }, { 0xc8, 0x80 }, |
318 | { 0x79, 0x0b }, { 0xc8, 0x01 }, | 318 | { 0x79, 0x0b }, { 0xc8, 0x01 }, |
319 | { 0x79, 0x0c }, { 0xc8, 0x0f }, | 319 | { 0x79, 0x0c }, { 0xc8, 0x0f }, |
320 | { 0x79, 0x0d }, { 0xc8, 0x20 }, | 320 | { 0x79, 0x0d }, { 0xc8, 0x20 }, |
321 | { 0x79, 0x09 }, { 0xc8, 0x80 }, | 321 | { 0x79, 0x09 }, { 0xc8, 0x80 }, |
322 | { 0x79, 0x02 }, { 0xc8, 0xc0 }, | 322 | { 0x79, 0x02 }, { 0xc8, 0xc0 }, |
323 | { 0x79, 0x03 }, { 0xc8, 0x40 }, | 323 | { 0x79, 0x03 }, { 0xc8, 0x40 }, |
324 | { 0x79, 0x05 }, { 0xc8, 0x30 }, | 324 | { 0x79, 0x05 }, { 0xc8, 0x30 }, |
325 | { 0x79, 0x26 }, | 325 | { 0x79, 0x26 }, |
326 | 326 | ||
327 | { 0xff, 0xff }, /* END MARKER */ | 327 | { 0xff, 0xff }, /* END MARKER */ |
328 | }; | 328 | }; |
329 | 329 | ||
330 | 330 | ||
331 | /* | 331 | /* |
332 | * Here we'll try to encapsulate the changes for just the output | 332 | * Here we'll try to encapsulate the changes for just the output |
333 | * video format. | 333 | * video format. |
334 | * | 334 | * |
335 | * RGB656 and YUV422 come from OV; RGB444 is homebrewed. | 335 | * RGB656 and YUV422 come from OV; RGB444 is homebrewed. |
336 | * | 336 | * |
337 | * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why. | 337 | * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why. |
338 | */ | 338 | */ |
339 | 339 | ||
340 | 340 | ||
341 | static struct regval_list ov7670_fmt_yuv422[] = { | 341 | static struct regval_list ov7670_fmt_yuv422[] = { |
342 | { REG_COM7, 0x0 }, /* Selects YUV mode */ | 342 | { REG_COM7, 0x0 }, /* Selects YUV mode */ |
343 | { REG_RGB444, 0 }, /* No RGB444 please */ | 343 | { REG_RGB444, 0 }, /* No RGB444 please */ |
344 | { REG_COM1, 0 }, | 344 | { REG_COM1, 0 }, |
345 | { REG_COM15, COM15_R00FF }, | 345 | { REG_COM15, COM15_R00FF }, |
346 | { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ | 346 | { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ |
347 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ | 347 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ |
348 | { 0x50, 0x80 }, /* "matrix coefficient 2" */ | 348 | { 0x50, 0x80 }, /* "matrix coefficient 2" */ |
349 | { 0x51, 0 }, /* vb */ | 349 | { 0x51, 0 }, /* vb */ |
350 | { 0x52, 0x22 }, /* "matrix coefficient 4" */ | 350 | { 0x52, 0x22 }, /* "matrix coefficient 4" */ |
351 | { 0x53, 0x5e }, /* "matrix coefficient 5" */ | 351 | { 0x53, 0x5e }, /* "matrix coefficient 5" */ |
352 | { 0x54, 0x80 }, /* "matrix coefficient 6" */ | 352 | { 0x54, 0x80 }, /* "matrix coefficient 6" */ |
353 | { REG_COM13, COM13_GAMMA|COM13_UVSAT }, | 353 | { REG_COM13, COM13_GAMMA|COM13_UVSAT }, |
354 | { 0xff, 0xff }, | 354 | { 0xff, 0xff }, |
355 | }; | 355 | }; |
356 | 356 | ||
357 | static struct regval_list ov7670_fmt_rgb565[] = { | 357 | static struct regval_list ov7670_fmt_rgb565[] = { |
358 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ | 358 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ |
359 | { REG_RGB444, 0 }, /* No RGB444 please */ | 359 | { REG_RGB444, 0 }, /* No RGB444 please */ |
360 | { REG_COM1, 0x0 }, | 360 | { REG_COM1, 0x0 }, |
361 | { REG_COM15, COM15_RGB565 }, | 361 | { REG_COM15, COM15_RGB565 }, |
362 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ | 362 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ |
363 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ | 363 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ |
364 | { 0x50, 0xb3 }, /* "matrix coefficient 2" */ | 364 | { 0x50, 0xb3 }, /* "matrix coefficient 2" */ |
365 | { 0x51, 0 }, /* vb */ | 365 | { 0x51, 0 }, /* vb */ |
366 | { 0x52, 0x3d }, /* "matrix coefficient 4" */ | 366 | { 0x52, 0x3d }, /* "matrix coefficient 4" */ |
367 | { 0x53, 0xa7 }, /* "matrix coefficient 5" */ | 367 | { 0x53, 0xa7 }, /* "matrix coefficient 5" */ |
368 | { 0x54, 0xe4 }, /* "matrix coefficient 6" */ | 368 | { 0x54, 0xe4 }, /* "matrix coefficient 6" */ |
369 | { REG_COM13, COM13_GAMMA|COM13_UVSAT }, | 369 | { REG_COM13, COM13_GAMMA|COM13_UVSAT }, |
370 | { 0xff, 0xff }, | 370 | { 0xff, 0xff }, |
371 | }; | 371 | }; |
372 | 372 | ||
373 | static struct regval_list ov7670_fmt_rgb444[] = { | 373 | static struct regval_list ov7670_fmt_rgb444[] = { |
374 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ | 374 | { REG_COM7, COM7_RGB }, /* Selects RGB mode */ |
375 | { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ | 375 | { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ |
376 | { REG_COM1, 0x40 }, /* Magic reserved bit */ | 376 | { REG_COM1, 0x40 }, /* Magic reserved bit */ |
377 | { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ | 377 | { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ |
378 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ | 378 | { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ |
379 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ | 379 | { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ |
380 | { 0x50, 0xb3 }, /* "matrix coefficient 2" */ | 380 | { 0x50, 0xb3 }, /* "matrix coefficient 2" */ |
381 | { 0x51, 0 }, /* vb */ | 381 | { 0x51, 0 }, /* vb */ |
382 | { 0x52, 0x3d }, /* "matrix coefficient 4" */ | 382 | { 0x52, 0x3d }, /* "matrix coefficient 4" */ |
383 | { 0x53, 0xa7 }, /* "matrix coefficient 5" */ | 383 | { 0x53, 0xa7 }, /* "matrix coefficient 5" */ |
384 | { 0x54, 0xe4 }, /* "matrix coefficient 6" */ | 384 | { 0x54, 0xe4 }, /* "matrix coefficient 6" */ |
385 | { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */ | 385 | { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */ |
386 | { 0xff, 0xff }, | 386 | { 0xff, 0xff }, |
387 | }; | 387 | }; |
388 | 388 | ||
389 | static struct regval_list ov7670_fmt_raw[] = { | 389 | static struct regval_list ov7670_fmt_raw[] = { |
390 | { REG_COM7, COM7_BAYER }, | 390 | { REG_COM7, COM7_BAYER }, |
391 | { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ | 391 | { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ |
392 | { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ | 392 | { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ |
393 | { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ | 393 | { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ |
394 | { 0xff, 0xff }, | 394 | { 0xff, 0xff }, |
395 | }; | 395 | }; |
396 | 396 | ||
397 | 397 | ||
398 | 398 | ||
399 | /* | 399 | /* |
400 | * Low-level register I/O. | 400 | * Low-level register I/O. |
401 | */ | 401 | */ |
402 | 402 | ||
403 | static int ov7670_read(struct i2c_client *c, unsigned char reg, | 403 | static int ov7670_read(struct i2c_client *c, unsigned char reg, |
404 | unsigned char *value) | 404 | unsigned char *value) |
405 | { | 405 | { |
406 | int ret; | 406 | int ret; |
407 | 407 | ||
408 | ret = i2c_smbus_read_byte_data(c, reg); | 408 | ret = i2c_smbus_read_byte_data(c, reg); |
409 | if (ret >= 0) { | 409 | if (ret >= 0) { |
410 | *value = (unsigned char) ret; | 410 | *value = (unsigned char) ret; |
411 | ret = 0; | 411 | ret = 0; |
412 | } | 412 | } |
413 | return ret; | 413 | return ret; |
414 | } | 414 | } |
415 | 415 | ||
416 | 416 | ||
417 | static int ov7670_write(struct i2c_client *c, unsigned char reg, | 417 | static int ov7670_write(struct i2c_client *c, unsigned char reg, |
418 | unsigned char value) | 418 | unsigned char value) |
419 | { | 419 | { |
420 | int ret = i2c_smbus_write_byte_data(c, reg, value); | 420 | int ret = i2c_smbus_write_byte_data(c, reg, value); |
421 | if (reg == REG_COM7 && (value & COM7_RESET)) | 421 | if (reg == REG_COM7 && (value & COM7_RESET)) |
422 | msleep(2); /* Wait for reset to run */ | 422 | msleep(2); /* Wait for reset to run */ |
423 | return ret; | 423 | return ret; |
424 | } | 424 | } |
425 | 425 | ||
426 | 426 | ||
427 | /* | 427 | /* |
428 | * Write a list of register settings; ff/ff stops the process. | 428 | * Write a list of register settings; ff/ff stops the process. |
429 | */ | 429 | */ |
430 | static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) | 430 | static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) |
431 | { | 431 | { |
432 | while (vals->reg_num != 0xff || vals->value != 0xff) { | 432 | while (vals->reg_num != 0xff || vals->value != 0xff) { |
433 | int ret = ov7670_write(c, vals->reg_num, vals->value); | 433 | int ret = ov7670_write(c, vals->reg_num, vals->value); |
434 | if (ret < 0) | 434 | if (ret < 0) |
435 | return ret; | 435 | return ret; |
436 | vals++; | 436 | vals++; |
437 | } | 437 | } |
438 | return 0; | 438 | return 0; |
439 | } | 439 | } |
440 | 440 | ||
441 | 441 | ||
442 | /* | 442 | /* |
443 | * Stuff that knows about the sensor. | 443 | * Stuff that knows about the sensor. |
444 | */ | 444 | */ |
445 | static void ov7670_reset(struct i2c_client *client) | 445 | static void ov7670_reset(struct i2c_client *client) |
446 | { | 446 | { |
447 | ov7670_write(client, REG_COM7, COM7_RESET); | 447 | ov7670_write(client, REG_COM7, COM7_RESET); |
448 | msleep(1); | 448 | msleep(1); |
449 | } | 449 | } |
450 | 450 | ||
451 | 451 | ||
452 | static int ov7670_init(struct i2c_client *client) | 452 | static int ov7670_init(struct i2c_client *client) |
453 | { | 453 | { |
454 | return ov7670_write_array(client, ov7670_default_regs); | 454 | return ov7670_write_array(client, ov7670_default_regs); |
455 | } | 455 | } |
456 | 456 | ||
457 | 457 | ||
458 | 458 | ||
459 | static int ov7670_detect(struct i2c_client *client) | 459 | static int ov7670_detect(struct i2c_client *client) |
460 | { | 460 | { |
461 | unsigned char v; | 461 | unsigned char v; |
462 | int ret; | 462 | int ret; |
463 | 463 | ||
464 | ret = ov7670_init(client); | 464 | ret = ov7670_init(client); |
465 | if (ret < 0) | 465 | if (ret < 0) |
466 | return ret; | 466 | return ret; |
467 | ret = ov7670_read(client, REG_MIDH, &v); | 467 | ret = ov7670_read(client, REG_MIDH, &v); |
468 | if (ret < 0) | 468 | if (ret < 0) |
469 | return ret; | 469 | return ret; |
470 | if (v != 0x7f) /* OV manuf. id. */ | 470 | if (v != 0x7f) /* OV manuf. id. */ |
471 | return -ENODEV; | 471 | return -ENODEV; |
472 | ret = ov7670_read(client, REG_MIDL, &v); | 472 | ret = ov7670_read(client, REG_MIDL, &v); |
473 | if (ret < 0) | 473 | if (ret < 0) |
474 | return ret; | 474 | return ret; |
475 | if (v != 0xa2) | 475 | if (v != 0xa2) |
476 | return -ENODEV; | 476 | return -ENODEV; |
477 | /* | 477 | /* |
478 | * OK, we know we have an OmniVision chip...but which one? | 478 | * OK, we know we have an OmniVision chip...but which one? |
479 | */ | 479 | */ |
480 | ret = ov7670_read(client, REG_PID, &v); | 480 | ret = ov7670_read(client, REG_PID, &v); |
481 | if (ret < 0) | 481 | if (ret < 0) |
482 | return ret; | 482 | return ret; |
483 | if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ | 483 | if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ |
484 | return -ENODEV; | 484 | return -ENODEV; |
485 | ret = ov7670_read(client, REG_VER, &v); | 485 | ret = ov7670_read(client, REG_VER, &v); |
486 | if (ret < 0) | 486 | if (ret < 0) |
487 | return ret; | 487 | return ret; |
488 | if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ | 488 | if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ |
489 | return -ENODEV; | 489 | return -ENODEV; |
490 | return 0; | 490 | return 0; |
491 | } | 491 | } |
492 | 492 | ||
493 | 493 | ||
494 | /* | 494 | /* |
495 | * Store information about the video data format. The color matrix | 495 | * Store information about the video data format. The color matrix |
496 | * is deeply tied into the format, so keep the relevant values here. | 496 | * is deeply tied into the format, so keep the relevant values here. |
497 | * The magic matrix nubmers come from OmniVision. | 497 | * The magic matrix nubmers come from OmniVision. |
498 | */ | 498 | */ |
499 | static struct ov7670_format_struct { | 499 | static struct ov7670_format_struct { |
500 | __u8 *desc; | 500 | __u8 *desc; |
501 | __u32 pixelformat; | 501 | __u32 pixelformat; |
502 | struct regval_list *regs; | 502 | struct regval_list *regs; |
503 | int cmatrix[CMATRIX_LEN]; | 503 | int cmatrix[CMATRIX_LEN]; |
504 | int bpp; /* Bytes per pixel */ | 504 | int bpp; /* Bytes per pixel */ |
505 | } ov7670_formats[] = { | 505 | } ov7670_formats[] = { |
506 | { | 506 | { |
507 | .desc = "YUYV 4:2:2", | 507 | .desc = "YUYV 4:2:2", |
508 | .pixelformat = V4L2_PIX_FMT_YUYV, | 508 | .pixelformat = V4L2_PIX_FMT_YUYV, |
509 | .regs = ov7670_fmt_yuv422, | 509 | .regs = ov7670_fmt_yuv422, |
510 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, | 510 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, |
511 | .bpp = 2, | 511 | .bpp = 2, |
512 | }, | 512 | }, |
513 | { | 513 | { |
514 | .desc = "RGB 444", | 514 | .desc = "RGB 444", |
515 | .pixelformat = V4L2_PIX_FMT_RGB444, | 515 | .pixelformat = V4L2_PIX_FMT_RGB444, |
516 | .regs = ov7670_fmt_rgb444, | 516 | .regs = ov7670_fmt_rgb444, |
517 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 517 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
518 | .bpp = 2, | 518 | .bpp = 2, |
519 | }, | 519 | }, |
520 | { | 520 | { |
521 | .desc = "RGB 565", | 521 | .desc = "RGB 565", |
522 | .pixelformat = V4L2_PIX_FMT_RGB565, | 522 | .pixelformat = V4L2_PIX_FMT_RGB565, |
523 | .regs = ov7670_fmt_rgb565, | 523 | .regs = ov7670_fmt_rgb565, |
524 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 524 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
525 | .bpp = 2, | 525 | .bpp = 2, |
526 | }, | 526 | }, |
527 | { | 527 | { |
528 | .desc = "Raw RGB Bayer", | 528 | .desc = "Raw RGB Bayer", |
529 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | 529 | .pixelformat = V4L2_PIX_FMT_SBGGR8, |
530 | .regs = ov7670_fmt_raw, | 530 | .regs = ov7670_fmt_raw, |
531 | .cmatrix = { 0, 0, 0, 0, 0, 0 }, | 531 | .cmatrix = { 0, 0, 0, 0, 0, 0 }, |
532 | .bpp = 1 | 532 | .bpp = 1 |
533 | }, | 533 | }, |
534 | }; | 534 | }; |
535 | #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) | 535 | #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) |
536 | 536 | ||
537 | 537 | ||
538 | /* | 538 | /* |
539 | * Then there is the issue of window sizes. Try to capture the info here. | 539 | * Then there is the issue of window sizes. Try to capture the info here. |
540 | */ | 540 | */ |
541 | 541 | ||
542 | /* | 542 | /* |
543 | * QCIF mode is done (by OV) in a very strange way - it actually looks like | 543 | * QCIF mode is done (by OV) in a very strange way - it actually looks like |
544 | * VGA with weird scaling options - they do *not* use the canned QCIF mode | 544 | * VGA with weird scaling options - they do *not* use the canned QCIF mode |
545 | * which is allegedly provided by the sensor. So here's the weird register | 545 | * which is allegedly provided by the sensor. So here's the weird register |
546 | * settings. | 546 | * settings. |
547 | */ | 547 | */ |
548 | static struct regval_list ov7670_qcif_regs[] = { | 548 | static struct regval_list ov7670_qcif_regs[] = { |
549 | { REG_COM3, COM3_SCALEEN|COM3_DCWEN }, | 549 | { REG_COM3, COM3_SCALEEN|COM3_DCWEN }, |
550 | { REG_COM3, COM3_DCWEN }, | 550 | { REG_COM3, COM3_DCWEN }, |
551 | { REG_COM14, COM14_DCWEN | 0x01}, | 551 | { REG_COM14, COM14_DCWEN | 0x01}, |
552 | { 0x73, 0xf1 }, | 552 | { 0x73, 0xf1 }, |
553 | { 0xa2, 0x52 }, | 553 | { 0xa2, 0x52 }, |
554 | { 0x7b, 0x1c }, | 554 | { 0x7b, 0x1c }, |
555 | { 0x7c, 0x28 }, | 555 | { 0x7c, 0x28 }, |
556 | { 0x7d, 0x3c }, | 556 | { 0x7d, 0x3c }, |
557 | { 0x7f, 0x69 }, | 557 | { 0x7f, 0x69 }, |
558 | { REG_COM9, 0x38 }, | 558 | { REG_COM9, 0x38 }, |
559 | { 0xa1, 0x0b }, | 559 | { 0xa1, 0x0b }, |
560 | { 0x74, 0x19 }, | 560 | { 0x74, 0x19 }, |
561 | { 0x9a, 0x80 }, | 561 | { 0x9a, 0x80 }, |
562 | { 0x43, 0x14 }, | 562 | { 0x43, 0x14 }, |
563 | { REG_COM13, 0xc0 }, | 563 | { REG_COM13, 0xc0 }, |
564 | { 0xff, 0xff }, | 564 | { 0xff, 0xff }, |
565 | }; | 565 | }; |
566 | 566 | ||
567 | static struct ov7670_win_size { | 567 | static struct ov7670_win_size { |
568 | int width; | 568 | int width; |
569 | int height; | 569 | int height; |
570 | unsigned char com7_bit; | 570 | unsigned char com7_bit; |
571 | int hstart; /* Start/stop values for the camera. Note */ | 571 | int hstart; /* Start/stop values for the camera. Note */ |
572 | int hstop; /* that they do not always make complete */ | 572 | int hstop; /* that they do not always make complete */ |
573 | int vstart; /* sense to humans, but evidently the sensor */ | 573 | int vstart; /* sense to humans, but evidently the sensor */ |
574 | int vstop; /* will do the right thing... */ | 574 | int vstop; /* will do the right thing... */ |
575 | struct regval_list *regs; /* Regs to tweak */ | 575 | struct regval_list *regs; /* Regs to tweak */ |
576 | /* h/vref stuff */ | 576 | /* h/vref stuff */ |
577 | } ov7670_win_sizes[] = { | 577 | } ov7670_win_sizes[] = { |
578 | /* VGA */ | 578 | /* VGA */ |
579 | { | 579 | { |
580 | .width = VGA_WIDTH, | 580 | .width = VGA_WIDTH, |
581 | .height = VGA_HEIGHT, | 581 | .height = VGA_HEIGHT, |
582 | .com7_bit = COM7_FMT_VGA, | 582 | .com7_bit = COM7_FMT_VGA, |
583 | .hstart = 158, /* These values from */ | 583 | .hstart = 158, /* These values from */ |
584 | .hstop = 14, /* Omnivision */ | 584 | .hstop = 14, /* Omnivision */ |
585 | .vstart = 10, | 585 | .vstart = 10, |
586 | .vstop = 490, | 586 | .vstop = 490, |
587 | .regs = NULL, | 587 | .regs = NULL, |
588 | }, | 588 | }, |
589 | /* CIF */ | 589 | /* CIF */ |
590 | { | 590 | { |
591 | .width = CIF_WIDTH, | 591 | .width = CIF_WIDTH, |
592 | .height = CIF_HEIGHT, | 592 | .height = CIF_HEIGHT, |
593 | .com7_bit = COM7_FMT_CIF, | 593 | .com7_bit = COM7_FMT_CIF, |
594 | .hstart = 170, /* Empirically determined */ | 594 | .hstart = 170, /* Empirically determined */ |
595 | .hstop = 90, | 595 | .hstop = 90, |
596 | .vstart = 14, | 596 | .vstart = 14, |
597 | .vstop = 494, | 597 | .vstop = 494, |
598 | .regs = NULL, | 598 | .regs = NULL, |
599 | }, | 599 | }, |
600 | /* QVGA */ | 600 | /* QVGA */ |
601 | { | 601 | { |
602 | .width = QVGA_WIDTH, | 602 | .width = QVGA_WIDTH, |
603 | .height = QVGA_HEIGHT, | 603 | .height = QVGA_HEIGHT, |
604 | .com7_bit = COM7_FMT_QVGA, | 604 | .com7_bit = COM7_FMT_QVGA, |
605 | .hstart = 164, /* Empirically determined */ | 605 | .hstart = 164, /* Empirically determined */ |
606 | .hstop = 20, | 606 | .hstop = 20, |
607 | .vstart = 14, | 607 | .vstart = 14, |
608 | .vstop = 494, | 608 | .vstop = 494, |
609 | .regs = NULL, | 609 | .regs = NULL, |
610 | }, | 610 | }, |
611 | /* QCIF */ | 611 | /* QCIF */ |
612 | { | 612 | { |
613 | .width = QCIF_WIDTH, | 613 | .width = QCIF_WIDTH, |
614 | .height = QCIF_HEIGHT, | 614 | .height = QCIF_HEIGHT, |
615 | .com7_bit = COM7_FMT_VGA, /* see comment above */ | 615 | .com7_bit = COM7_FMT_VGA, /* see comment above */ |
616 | .hstart = 456, /* Empirically determined */ | 616 | .hstart = 456, /* Empirically determined */ |
617 | .hstop = 24, | 617 | .hstop = 24, |
618 | .vstart = 14, | 618 | .vstart = 14, |
619 | .vstop = 494, | 619 | .vstop = 494, |
620 | .regs = ov7670_qcif_regs, | 620 | .regs = ov7670_qcif_regs, |
621 | }, | 621 | }, |
622 | }; | 622 | }; |
623 | 623 | ||
624 | #define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes)) | 624 | #define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes)) |
625 | 625 | ||
626 | 626 | ||
627 | /* | 627 | /* |
628 | * Store a set of start/stop values into the camera. | 628 | * Store a set of start/stop values into the camera. |
629 | */ | 629 | */ |
630 | static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, | 630 | static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, |
631 | int vstart, int vstop) | 631 | int vstart, int vstop) |
632 | { | 632 | { |
633 | int ret; | 633 | int ret; |
634 | unsigned char v; | 634 | unsigned char v; |
635 | /* | 635 | /* |
636 | * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of | 636 | * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of |
637 | * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is | 637 | * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is |
638 | * a mystery "edge offset" value in the top two bits of href. | 638 | * a mystery "edge offset" value in the top two bits of href. |
639 | */ | 639 | */ |
640 | ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); | 640 | ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); |
641 | ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); | 641 | ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); |
642 | ret += ov7670_read(client, REG_HREF, &v); | 642 | ret += ov7670_read(client, REG_HREF, &v); |
643 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); | 643 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); |
644 | msleep(10); | 644 | msleep(10); |
645 | ret += ov7670_write(client, REG_HREF, v); | 645 | ret += ov7670_write(client, REG_HREF, v); |
646 | /* | 646 | /* |
647 | * Vertical: similar arrangement, but only 10 bits. | 647 | * Vertical: similar arrangement, but only 10 bits. |
648 | */ | 648 | */ |
649 | ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); | 649 | ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); |
650 | ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); | 650 | ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); |
651 | ret += ov7670_read(client, REG_VREF, &v); | 651 | ret += ov7670_read(client, REG_VREF, &v); |
652 | v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); | 652 | v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); |
653 | msleep(10); | 653 | msleep(10); |
654 | ret += ov7670_write(client, REG_VREF, v); | 654 | ret += ov7670_write(client, REG_VREF, v); |
655 | return ret; | 655 | return ret; |
656 | } | 656 | } |
657 | 657 | ||
658 | 658 | ||
659 | static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) | 659 | static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) |
660 | { | 660 | { |
661 | struct ov7670_format_struct *ofmt; | 661 | struct ov7670_format_struct *ofmt; |
662 | 662 | ||
663 | if (fmt->index >= N_OV7670_FMTS) | 663 | if (fmt->index >= N_OV7670_FMTS) |
664 | return -EINVAL; | 664 | return -EINVAL; |
665 | 665 | ||
666 | ofmt = ov7670_formats + fmt->index; | 666 | ofmt = ov7670_formats + fmt->index; |
667 | fmt->flags = 0; | 667 | fmt->flags = 0; |
668 | strcpy(fmt->description, ofmt->desc); | 668 | strcpy(fmt->description, ofmt->desc); |
669 | fmt->pixelformat = ofmt->pixelformat; | 669 | fmt->pixelformat = ofmt->pixelformat; |
670 | return 0; | 670 | return 0; |
671 | } | 671 | } |
672 | 672 | ||
673 | 673 | ||
674 | static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, | 674 | static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, |
675 | struct ov7670_format_struct **ret_fmt, | 675 | struct ov7670_format_struct **ret_fmt, |
676 | struct ov7670_win_size **ret_wsize) | 676 | struct ov7670_win_size **ret_wsize) |
677 | { | 677 | { |
678 | int index; | 678 | int index; |
679 | struct ov7670_win_size *wsize; | 679 | struct ov7670_win_size *wsize; |
680 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | 680 | struct v4l2_pix_format *pix = &fmt->fmt.pix; |
681 | 681 | ||
682 | for (index = 0; index < N_OV7670_FMTS; index++) | 682 | for (index = 0; index < N_OV7670_FMTS; index++) |
683 | if (ov7670_formats[index].pixelformat == pix->pixelformat) | 683 | if (ov7670_formats[index].pixelformat == pix->pixelformat) |
684 | break; | 684 | break; |
685 | if (index >= N_OV7670_FMTS) { | 685 | if (index >= N_OV7670_FMTS) { |
686 | /* default to first format */ | 686 | /* default to first format */ |
687 | index = 0; | 687 | index = 0; |
688 | pix->pixelformat = ov7670_formats[0].pixelformat; | 688 | pix->pixelformat = ov7670_formats[0].pixelformat; |
689 | } | 689 | } |
690 | if (ret_fmt != NULL) | 690 | if (ret_fmt != NULL) |
691 | *ret_fmt = ov7670_formats + index; | 691 | *ret_fmt = ov7670_formats + index; |
692 | /* | 692 | /* |
693 | * Fields: the OV devices claim to be progressive. | 693 | * Fields: the OV devices claim to be progressive. |
694 | */ | 694 | */ |
695 | pix->field = V4L2_FIELD_NONE; | 695 | pix->field = V4L2_FIELD_NONE; |
696 | /* | 696 | /* |
697 | * Round requested image size down to the nearest | 697 | * Round requested image size down to the nearest |
698 | * we support, but not below the smallest. | 698 | * we support, but not below the smallest. |
699 | */ | 699 | */ |
700 | for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; | 700 | for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; |
701 | wsize++) | 701 | wsize++) |
702 | if (pix->width >= wsize->width && pix->height >= wsize->height) | 702 | if (pix->width >= wsize->width && pix->height >= wsize->height) |
703 | break; | 703 | break; |
704 | if (wsize >= ov7670_win_sizes + N_WIN_SIZES) | 704 | if (wsize >= ov7670_win_sizes + N_WIN_SIZES) |
705 | wsize--; /* Take the smallest one */ | 705 | wsize--; /* Take the smallest one */ |
706 | if (ret_wsize != NULL) | 706 | if (ret_wsize != NULL) |
707 | *ret_wsize = wsize; | 707 | *ret_wsize = wsize; |
708 | /* | 708 | /* |
709 | * Note the size we'll actually handle. | 709 | * Note the size we'll actually handle. |
710 | */ | 710 | */ |
711 | pix->width = wsize->width; | 711 | pix->width = wsize->width; |
712 | pix->height = wsize->height; | 712 | pix->height = wsize->height; |
713 | pix->bytesperline = pix->width*ov7670_formats[index].bpp; | 713 | pix->bytesperline = pix->width*ov7670_formats[index].bpp; |
714 | pix->sizeimage = pix->height*pix->bytesperline; | 714 | pix->sizeimage = pix->height*pix->bytesperline; |
715 | return 0; | 715 | return 0; |
716 | } | 716 | } |
717 | 717 | ||
718 | /* | 718 | /* |
719 | * Set a format. | 719 | * Set a format. |
720 | */ | 720 | */ |
721 | static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | 721 | static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) |
722 | { | 722 | { |
723 | int ret; | 723 | int ret; |
724 | struct ov7670_format_struct *ovfmt; | 724 | struct ov7670_format_struct *ovfmt; |
725 | struct ov7670_win_size *wsize; | 725 | struct ov7670_win_size *wsize; |
726 | struct ov7670_info *info = i2c_get_clientdata(c); | 726 | struct ov7670_info *info = i2c_get_clientdata(c); |
727 | unsigned char com7, clkrc; | 727 | unsigned char com7, clkrc; |
728 | 728 | ||
729 | ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); | 729 | ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); |
730 | if (ret) | 730 | if (ret) |
731 | return ret; | 731 | return ret; |
732 | /* | 732 | /* |
733 | * HACK: if we're running rgb565 we need to grab then rewrite | 733 | * HACK: if we're running rgb565 we need to grab then rewrite |
734 | * CLKRC. If we're *not*, however, then rewriting clkrc hoses | 734 | * CLKRC. If we're *not*, however, then rewriting clkrc hoses |
735 | * the colors. | 735 | * the colors. |
736 | */ | 736 | */ |
737 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { | 737 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { |
738 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 738 | ret = ov7670_read(c, REG_CLKRC, &clkrc); |
739 | if (ret) | 739 | if (ret) |
740 | return ret; | 740 | return ret; |
741 | } | 741 | } |
742 | /* | 742 | /* |
743 | * COM7 is a pain in the ass, it doesn't like to be read then | 743 | * COM7 is a pain in the ass, it doesn't like to be read then |
744 | * quickly written afterward. But we have everything we need | 744 | * quickly written afterward. But we have everything we need |
745 | * to set it absolutely here, as long as the format-specific | 745 | * to set it absolutely here, as long as the format-specific |
746 | * register sets list it first. | 746 | * register sets list it first. |
747 | */ | 747 | */ |
748 | com7 = ovfmt->regs[0].value; | 748 | com7 = ovfmt->regs[0].value; |
749 | com7 |= wsize->com7_bit; | 749 | com7 |= wsize->com7_bit; |
750 | ov7670_write(c, REG_COM7, com7); | 750 | ov7670_write(c, REG_COM7, com7); |
751 | /* | 751 | /* |
752 | * Now write the rest of the array. Also store start/stops | 752 | * Now write the rest of the array. Also store start/stops |
753 | */ | 753 | */ |
754 | ov7670_write_array(c, ovfmt->regs + 1); | 754 | ov7670_write_array(c, ovfmt->regs + 1); |
755 | ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, | 755 | ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, |
756 | wsize->vstop); | 756 | wsize->vstop); |
757 | ret = 0; | 757 | ret = 0; |
758 | if (wsize->regs) | 758 | if (wsize->regs) |
759 | ret = ov7670_write_array(c, wsize->regs); | 759 | ret = ov7670_write_array(c, wsize->regs); |
760 | info->fmt = ovfmt; | 760 | info->fmt = ovfmt; |
761 | 761 | ||
762 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) | 762 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) |
763 | ret = ov7670_write(c, REG_CLKRC, clkrc); | 763 | ret = ov7670_write(c, REG_CLKRC, clkrc); |
764 | return ret; | 764 | return ret; |
765 | } | 765 | } |
766 | 766 | ||
767 | /* | 767 | /* |
768 | * Implement G/S_PARM. There is a "high quality" mode we could try | 768 | * Implement G/S_PARM. There is a "high quality" mode we could try |
769 | * to do someday; for now, we just do the frame rate tweak. | 769 | * to do someday; for now, we just do the frame rate tweak. |
770 | */ | 770 | */ |
771 | static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | 771 | static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) |
772 | { | 772 | { |
773 | struct v4l2_captureparm *cp = &parms->parm.capture; | 773 | struct v4l2_captureparm *cp = &parms->parm.capture; |
774 | unsigned char clkrc; | 774 | unsigned char clkrc; |
775 | int ret; | 775 | int ret; |
776 | 776 | ||
777 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 777 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
778 | return -EINVAL; | 778 | return -EINVAL; |
779 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 779 | ret = ov7670_read(c, REG_CLKRC, &clkrc); |
780 | if (ret < 0) | 780 | if (ret < 0) |
781 | return ret; | 781 | return ret; |
782 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | 782 | memset(cp, 0, sizeof(struct v4l2_captureparm)); |
783 | cp->capability = V4L2_CAP_TIMEPERFRAME; | 783 | cp->capability = V4L2_CAP_TIMEPERFRAME; |
784 | cp->timeperframe.numerator = 1; | 784 | cp->timeperframe.numerator = 1; |
785 | cp->timeperframe.denominator = OV7670_FRAME_RATE; | 785 | cp->timeperframe.denominator = OV7670_FRAME_RATE; |
786 | if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1) | 786 | if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1) |
787 | cp->timeperframe.denominator /= (clkrc & CLK_SCALE); | 787 | cp->timeperframe.denominator /= (clkrc & CLK_SCALE); |
788 | return 0; | 788 | return 0; |
789 | } | 789 | } |
790 | 790 | ||
791 | static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | 791 | static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) |
792 | { | 792 | { |
793 | struct v4l2_captureparm *cp = &parms->parm.capture; | 793 | struct v4l2_captureparm *cp = &parms->parm.capture; |
794 | struct v4l2_fract *tpf = &cp->timeperframe; | 794 | struct v4l2_fract *tpf = &cp->timeperframe; |
795 | unsigned char clkrc; | 795 | unsigned char clkrc; |
796 | int ret, div; | 796 | int ret, div; |
797 | 797 | ||
798 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 798 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
799 | return -EINVAL; | 799 | return -EINVAL; |
800 | if (cp->extendedmode != 0) | 800 | if (cp->extendedmode != 0) |
801 | return -EINVAL; | 801 | return -EINVAL; |
802 | /* | 802 | /* |
803 | * CLKRC has a reserved bit, so let's preserve it. | 803 | * CLKRC has a reserved bit, so let's preserve it. |
804 | */ | 804 | */ |
805 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 805 | ret = ov7670_read(c, REG_CLKRC, &clkrc); |
806 | if (ret < 0) | 806 | if (ret < 0) |
807 | return ret; | 807 | return ret; |
808 | if (tpf->numerator == 0 || tpf->denominator == 0) | 808 | if (tpf->numerator == 0 || tpf->denominator == 0) |
809 | div = 1; /* Reset to full rate */ | 809 | div = 1; /* Reset to full rate */ |
810 | else | 810 | else |
811 | div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator; | 811 | div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator; |
812 | if (div == 0) | 812 | if (div == 0) |
813 | div = 1; | 813 | div = 1; |
814 | else if (div > CLK_SCALE) | 814 | else if (div > CLK_SCALE) |
815 | div = CLK_SCALE; | 815 | div = CLK_SCALE; |
816 | clkrc = (clkrc & 0x80) | div; | 816 | clkrc = (clkrc & 0x80) | div; |
817 | tpf->numerator = 1; | 817 | tpf->numerator = 1; |
818 | tpf->denominator = OV7670_FRAME_RATE/div; | 818 | tpf->denominator = OV7670_FRAME_RATE/div; |
819 | return ov7670_write(c, REG_CLKRC, clkrc); | 819 | return ov7670_write(c, REG_CLKRC, clkrc); |
820 | } | 820 | } |
821 | 821 | ||
822 | 822 | ||
823 | 823 | ||
824 | /* | 824 | /* |
825 | * Code for dealing with controls. | 825 | * Code for dealing with controls. |
826 | */ | 826 | */ |
827 | 827 | ||
828 | 828 | ||
829 | 829 | ||
830 | 830 | ||
831 | 831 | ||
832 | static int ov7670_store_cmatrix(struct i2c_client *client, | 832 | static int ov7670_store_cmatrix(struct i2c_client *client, |
833 | int matrix[CMATRIX_LEN]) | 833 | int matrix[CMATRIX_LEN]) |
834 | { | 834 | { |
835 | int i, ret; | 835 | int i, ret; |
836 | unsigned char signbits = 0; | 836 | unsigned char signbits = 0; |
837 | 837 | ||
838 | /* | 838 | /* |
839 | * Weird crap seems to exist in the upper part of | 839 | * Weird crap seems to exist in the upper part of |
840 | * the sign bits register, so let's preserve it. | 840 | * the sign bits register, so let's preserve it. |
841 | */ | 841 | */ |
842 | ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); | 842 | ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); |
843 | signbits &= 0xc0; | 843 | signbits &= 0xc0; |
844 | 844 | ||
845 | for (i = 0; i < CMATRIX_LEN; i++) { | 845 | for (i = 0; i < CMATRIX_LEN; i++) { |
846 | unsigned char raw; | 846 | unsigned char raw; |
847 | 847 | ||
848 | if (matrix[i] < 0) { | 848 | if (matrix[i] < 0) { |
849 | signbits |= (1 << i); | 849 | signbits |= (1 << i); |
850 | if (matrix[i] < -255) | 850 | if (matrix[i] < -255) |
851 | raw = 0xff; | 851 | raw = 0xff; |
852 | else | 852 | else |
853 | raw = (-1 * matrix[i]) & 0xff; | 853 | raw = (-1 * matrix[i]) & 0xff; |
854 | } | 854 | } |
855 | else { | 855 | else { |
856 | if (matrix[i] > 255) | 856 | if (matrix[i] > 255) |
857 | raw = 0xff; | 857 | raw = 0xff; |
858 | else | 858 | else |
859 | raw = matrix[i] & 0xff; | 859 | raw = matrix[i] & 0xff; |
860 | } | 860 | } |
861 | ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); | 861 | ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); |
862 | } | 862 | } |
863 | ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); | 863 | ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); |
864 | return ret; | 864 | return ret; |
865 | } | 865 | } |
866 | 866 | ||
867 | 867 | ||
868 | /* | 868 | /* |
869 | * Hue also requires messing with the color matrix. It also requires | 869 | * Hue also requires messing with the color matrix. It also requires |
870 | * trig functions, which tend not to be well supported in the kernel. | 870 | * trig functions, which tend not to be well supported in the kernel. |
871 | * So here is a simple table of sine values, 0-90 degrees, in steps | 871 | * So here is a simple table of sine values, 0-90 degrees, in steps |
872 | * of five degrees. Values are multiplied by 1000. | 872 | * of five degrees. Values are multiplied by 1000. |
873 | * | 873 | * |
874 | * The following naive approximate trig functions require an argument | 874 | * The following naive approximate trig functions require an argument |
875 | * carefully limited to -180 <= theta <= 180. | 875 | * carefully limited to -180 <= theta <= 180. |
876 | */ | 876 | */ |
877 | #define SIN_STEP 5 | 877 | #define SIN_STEP 5 |
878 | static const int ov7670_sin_table[] = { | 878 | static const int ov7670_sin_table[] = { |
879 | 0, 87, 173, 258, 342, 422, | 879 | 0, 87, 173, 258, 342, 422, |
880 | 499, 573, 642, 707, 766, 819, | 880 | 499, 573, 642, 707, 766, 819, |
881 | 866, 906, 939, 965, 984, 996, | 881 | 866, 906, 939, 965, 984, 996, |
882 | 1000 | 882 | 1000 |
883 | }; | 883 | }; |
884 | 884 | ||
885 | static int ov7670_sine(int theta) | 885 | static int ov7670_sine(int theta) |
886 | { | 886 | { |
887 | int chs = 1; | 887 | int chs = 1; |
888 | int sine; | 888 | int sine; |
889 | 889 | ||
890 | if (theta < 0) { | 890 | if (theta < 0) { |
891 | theta = -theta; | 891 | theta = -theta; |
892 | chs = -1; | 892 | chs = -1; |
893 | } | 893 | } |
894 | if (theta <= 90) | 894 | if (theta <= 90) |
895 | sine = ov7670_sin_table[theta/SIN_STEP]; | 895 | sine = ov7670_sin_table[theta/SIN_STEP]; |
896 | else { | 896 | else { |
897 | theta -= 90; | 897 | theta -= 90; |
898 | sine = 1000 - ov7670_sin_table[theta/SIN_STEP]; | 898 | sine = 1000 - ov7670_sin_table[theta/SIN_STEP]; |
899 | } | 899 | } |
900 | return sine*chs; | 900 | return sine*chs; |
901 | } | 901 | } |
902 | 902 | ||
903 | static int ov7670_cosine(int theta) | 903 | static int ov7670_cosine(int theta) |
904 | { | 904 | { |
905 | theta = 90 - theta; | 905 | theta = 90 - theta; |
906 | if (theta > 180) | 906 | if (theta > 180) |
907 | theta -= 360; | 907 | theta -= 360; |
908 | else if (theta < -180) | 908 | else if (theta < -180) |
909 | theta += 360; | 909 | theta += 360; |
910 | return ov7670_sine(theta); | 910 | return ov7670_sine(theta); |
911 | } | 911 | } |
912 | 912 | ||
913 | 913 | ||
914 | 914 | ||
915 | 915 | ||
916 | static void ov7670_calc_cmatrix(struct ov7670_info *info, | 916 | static void ov7670_calc_cmatrix(struct ov7670_info *info, |
917 | int matrix[CMATRIX_LEN]) | 917 | int matrix[CMATRIX_LEN]) |
918 | { | 918 | { |
919 | int i; | 919 | int i; |
920 | /* | 920 | /* |
921 | * Apply the current saturation setting first. | 921 | * Apply the current saturation setting first. |
922 | */ | 922 | */ |
923 | for (i = 0; i < CMATRIX_LEN; i++) | 923 | for (i = 0; i < CMATRIX_LEN; i++) |
924 | matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; | 924 | matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; |
925 | /* | 925 | /* |
926 | * Then, if need be, rotate the hue value. | 926 | * Then, if need be, rotate the hue value. |
927 | */ | 927 | */ |
928 | if (info->hue != 0) { | 928 | if (info->hue != 0) { |
929 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; | 929 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; |
930 | 930 | ||
931 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); | 931 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); |
932 | sinth = ov7670_sine(info->hue); | 932 | sinth = ov7670_sine(info->hue); |
933 | costh = ov7670_cosine(info->hue); | 933 | costh = ov7670_cosine(info->hue); |
934 | 934 | ||
935 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; | 935 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; |
936 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; | 936 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; |
937 | matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000; | 937 | matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000; |
938 | matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000; | 938 | matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000; |
939 | matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000; | 939 | matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000; |
940 | matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000; | 940 | matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000; |
941 | } | 941 | } |
942 | } | 942 | } |
943 | 943 | ||
944 | 944 | ||
945 | 945 | ||
946 | static int ov7670_t_sat(struct i2c_client *client, int value) | 946 | static int ov7670_t_sat(struct i2c_client *client, int value) |
947 | { | 947 | { |
948 | struct ov7670_info *info = i2c_get_clientdata(client); | 948 | struct ov7670_info *info = i2c_get_clientdata(client); |
949 | int matrix[CMATRIX_LEN]; | 949 | int matrix[CMATRIX_LEN]; |
950 | int ret; | 950 | int ret; |
951 | 951 | ||
952 | info->sat = value; | 952 | info->sat = value; |
953 | ov7670_calc_cmatrix(info, matrix); | 953 | ov7670_calc_cmatrix(info, matrix); |
954 | ret = ov7670_store_cmatrix(client, matrix); | 954 | ret = ov7670_store_cmatrix(client, matrix); |
955 | return ret; | 955 | return ret; |
956 | } | 956 | } |
957 | 957 | ||
958 | static int ov7670_q_sat(struct i2c_client *client, __s32 *value) | 958 | static int ov7670_q_sat(struct i2c_client *client, __s32 *value) |
959 | { | 959 | { |
960 | struct ov7670_info *info = i2c_get_clientdata(client); | 960 | struct ov7670_info *info = i2c_get_clientdata(client); |
961 | 961 | ||
962 | *value = info->sat; | 962 | *value = info->sat; |
963 | return 0; | 963 | return 0; |
964 | } | 964 | } |
965 | 965 | ||
966 | static int ov7670_t_hue(struct i2c_client *client, int value) | 966 | static int ov7670_t_hue(struct i2c_client *client, int value) |
967 | { | 967 | { |
968 | struct ov7670_info *info = i2c_get_clientdata(client); | 968 | struct ov7670_info *info = i2c_get_clientdata(client); |
969 | int matrix[CMATRIX_LEN]; | 969 | int matrix[CMATRIX_LEN]; |
970 | int ret; | 970 | int ret; |
971 | 971 | ||
972 | if (value < -180 || value > 180) | 972 | if (value < -180 || value > 180) |
973 | return -EINVAL; | 973 | return -EINVAL; |
974 | info->hue = value; | 974 | info->hue = value; |
975 | ov7670_calc_cmatrix(info, matrix); | 975 | ov7670_calc_cmatrix(info, matrix); |
976 | ret = ov7670_store_cmatrix(client, matrix); | 976 | ret = ov7670_store_cmatrix(client, matrix); |
977 | return ret; | 977 | return ret; |
978 | } | 978 | } |
979 | 979 | ||
980 | 980 | ||
981 | static int ov7670_q_hue(struct i2c_client *client, __s32 *value) | 981 | static int ov7670_q_hue(struct i2c_client *client, __s32 *value) |
982 | { | 982 | { |
983 | struct ov7670_info *info = i2c_get_clientdata(client); | 983 | struct ov7670_info *info = i2c_get_clientdata(client); |
984 | 984 | ||
985 | *value = info->hue; | 985 | *value = info->hue; |
986 | return 0; | 986 | return 0; |
987 | } | 987 | } |
988 | 988 | ||
989 | 989 | ||
990 | /* | 990 | /* |
991 | * Some weird registers seem to store values in a sign/magnitude format! | 991 | * Some weird registers seem to store values in a sign/magnitude format! |
992 | */ | 992 | */ |
993 | static unsigned char ov7670_sm_to_abs(unsigned char v) | 993 | static unsigned char ov7670_sm_to_abs(unsigned char v) |
994 | { | 994 | { |
995 | if ((v & 0x80) == 0) | 995 | if ((v & 0x80) == 0) |
996 | return v + 128; | 996 | return v + 128; |
997 | else | 997 | else |
998 | return 128 - (v & 0x7f); | 998 | return 128 - (v & 0x7f); |
999 | } | 999 | } |
1000 | 1000 | ||
1001 | 1001 | ||
1002 | static unsigned char ov7670_abs_to_sm(unsigned char v) | 1002 | static unsigned char ov7670_abs_to_sm(unsigned char v) |
1003 | { | 1003 | { |
1004 | if (v > 127) | 1004 | if (v > 127) |
1005 | return v & 0x7f; | 1005 | return v & 0x7f; |
1006 | else | 1006 | else |
1007 | return (128 - v) | 0x80; | 1007 | return (128 - v) | 0x80; |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | static int ov7670_t_brightness(struct i2c_client *client, int value) | 1010 | static int ov7670_t_brightness(struct i2c_client *client, int value) |
1011 | { | 1011 | { |
1012 | unsigned char com8 = 0, v; | 1012 | unsigned char com8 = 0, v; |
1013 | int ret; | 1013 | int ret; |
1014 | 1014 | ||
1015 | ov7670_read(client, REG_COM8, &com8); | 1015 | ov7670_read(client, REG_COM8, &com8); |
1016 | com8 &= ~COM8_AEC; | 1016 | com8 &= ~COM8_AEC; |
1017 | ov7670_write(client, REG_COM8, com8); | 1017 | ov7670_write(client, REG_COM8, com8); |
1018 | v = ov7670_abs_to_sm(value); | 1018 | v = ov7670_abs_to_sm(value); |
1019 | ret = ov7670_write(client, REG_BRIGHT, v); | 1019 | ret = ov7670_write(client, REG_BRIGHT, v); |
1020 | return ret; | 1020 | return ret; |
1021 | } | 1021 | } |
1022 | 1022 | ||
1023 | static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) | 1023 | static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) |
1024 | { | 1024 | { |
1025 | unsigned char v = 0; | 1025 | unsigned char v = 0; |
1026 | int ret = ov7670_read(client, REG_BRIGHT, &v); | 1026 | int ret = ov7670_read(client, REG_BRIGHT, &v); |
1027 | 1027 | ||
1028 | *value = ov7670_sm_to_abs(v); | 1028 | *value = ov7670_sm_to_abs(v); |
1029 | return ret; | 1029 | return ret; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | static int ov7670_t_contrast(struct i2c_client *client, int value) | 1032 | static int ov7670_t_contrast(struct i2c_client *client, int value) |
1033 | { | 1033 | { |
1034 | return ov7670_write(client, REG_CONTRAS, (unsigned char) value); | 1034 | return ov7670_write(client, REG_CONTRAS, (unsigned char) value); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) | 1037 | static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) |
1038 | { | 1038 | { |
1039 | unsigned char v = 0; | 1039 | unsigned char v = 0; |
1040 | int ret = ov7670_read(client, REG_CONTRAS, &v); | 1040 | int ret = ov7670_read(client, REG_CONTRAS, &v); |
1041 | 1041 | ||
1042 | *value = v; | 1042 | *value = v; |
1043 | return ret; | 1043 | return ret; |
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) | 1046 | static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) |
1047 | { | 1047 | { |
1048 | int ret; | 1048 | int ret; |
1049 | unsigned char v = 0; | 1049 | unsigned char v = 0; |
1050 | 1050 | ||
1051 | ret = ov7670_read(client, REG_MVFP, &v); | 1051 | ret = ov7670_read(client, REG_MVFP, &v); |
1052 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; | 1052 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; |
1053 | return ret; | 1053 | return ret; |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | 1056 | ||
1057 | static int ov7670_t_hflip(struct i2c_client *client, int value) | 1057 | static int ov7670_t_hflip(struct i2c_client *client, int value) |
1058 | { | 1058 | { |
1059 | unsigned char v = 0; | 1059 | unsigned char v = 0; |
1060 | int ret; | 1060 | int ret; |
1061 | 1061 | ||
1062 | ret = ov7670_read(client, REG_MVFP, &v); | 1062 | ret = ov7670_read(client, REG_MVFP, &v); |
1063 | if (value) | 1063 | if (value) |
1064 | v |= MVFP_MIRROR; | 1064 | v |= MVFP_MIRROR; |
1065 | else | 1065 | else |
1066 | v &= ~MVFP_MIRROR; | 1066 | v &= ~MVFP_MIRROR; |
1067 | msleep(10); /* FIXME */ | 1067 | msleep(10); /* FIXME */ |
1068 | ret += ov7670_write(client, REG_MVFP, v); | 1068 | ret += ov7670_write(client, REG_MVFP, v); |
1069 | return ret; | 1069 | return ret; |
1070 | } | 1070 | } |
1071 | 1071 | ||
1072 | 1072 | ||
1073 | 1073 | ||
1074 | static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) | 1074 | static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) |
1075 | { | 1075 | { |
1076 | int ret; | 1076 | int ret; |
1077 | unsigned char v = 0; | 1077 | unsigned char v = 0; |
1078 | 1078 | ||
1079 | ret = ov7670_read(client, REG_MVFP, &v); | 1079 | ret = ov7670_read(client, REG_MVFP, &v); |
1080 | *value = (v & MVFP_FLIP) == MVFP_FLIP; | 1080 | *value = (v & MVFP_FLIP) == MVFP_FLIP; |
1081 | return ret; | 1081 | return ret; |
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | 1084 | ||
1085 | static int ov7670_t_vflip(struct i2c_client *client, int value) | 1085 | static int ov7670_t_vflip(struct i2c_client *client, int value) |
1086 | { | 1086 | { |
1087 | unsigned char v = 0; | 1087 | unsigned char v = 0; |
1088 | int ret; | 1088 | int ret; |
1089 | 1089 | ||
1090 | ret = ov7670_read(client, REG_MVFP, &v); | 1090 | ret = ov7670_read(client, REG_MVFP, &v); |
1091 | if (value) | 1091 | if (value) |
1092 | v |= MVFP_FLIP; | 1092 | v |= MVFP_FLIP; |
1093 | else | 1093 | else |
1094 | v &= ~MVFP_FLIP; | 1094 | v &= ~MVFP_FLIP; |
1095 | msleep(10); /* FIXME */ | 1095 | msleep(10); /* FIXME */ |
1096 | ret += ov7670_write(client, REG_MVFP, v); | 1096 | ret += ov7670_write(client, REG_MVFP, v); |
1097 | return ret; | 1097 | return ret; |
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | 1100 | ||
1101 | static struct ov7670_control { | 1101 | static struct ov7670_control { |
1102 | struct v4l2_queryctrl qc; | 1102 | struct v4l2_queryctrl qc; |
1103 | int (*query)(struct i2c_client *c, __s32 *value); | 1103 | int (*query)(struct i2c_client *c, __s32 *value); |
1104 | int (*tweak)(struct i2c_client *c, int value); | 1104 | int (*tweak)(struct i2c_client *c, int value); |
1105 | } ov7670_controls[] = | 1105 | } ov7670_controls[] = |
1106 | { | 1106 | { |
1107 | { | 1107 | { |
1108 | .qc = { | 1108 | .qc = { |
1109 | .id = V4L2_CID_BRIGHTNESS, | 1109 | .id = V4L2_CID_BRIGHTNESS, |
1110 | .type = V4L2_CTRL_TYPE_INTEGER, | 1110 | .type = V4L2_CTRL_TYPE_INTEGER, |
1111 | .name = "Brightness", | 1111 | .name = "Brightness", |
1112 | .minimum = 0, | 1112 | .minimum = 0, |
1113 | .maximum = 255, | 1113 | .maximum = 255, |
1114 | .step = 1, | 1114 | .step = 1, |
1115 | .default_value = 0x80, | 1115 | .default_value = 0x80, |
1116 | .flags = V4L2_CTRL_FLAG_SLIDER | 1116 | .flags = V4L2_CTRL_FLAG_SLIDER |
1117 | }, | 1117 | }, |
1118 | .tweak = ov7670_t_brightness, | 1118 | .tweak = ov7670_t_brightness, |
1119 | .query = ov7670_q_brightness, | 1119 | .query = ov7670_q_brightness, |
1120 | }, | 1120 | }, |
1121 | { | 1121 | { |
1122 | .qc = { | 1122 | .qc = { |
1123 | .id = V4L2_CID_CONTRAST, | 1123 | .id = V4L2_CID_CONTRAST, |
1124 | .type = V4L2_CTRL_TYPE_INTEGER, | 1124 | .type = V4L2_CTRL_TYPE_INTEGER, |
1125 | .name = "Contrast", | 1125 | .name = "Contrast", |
1126 | .minimum = 0, | 1126 | .minimum = 0, |
1127 | .maximum = 127, | 1127 | .maximum = 127, |
1128 | .step = 1, | 1128 | .step = 1, |
1129 | .default_value = 0x40, /* XXX ov7670 spec */ | 1129 | .default_value = 0x40, /* XXX ov7670 spec */ |
1130 | .flags = V4L2_CTRL_FLAG_SLIDER | 1130 | .flags = V4L2_CTRL_FLAG_SLIDER |
1131 | }, | 1131 | }, |
1132 | .tweak = ov7670_t_contrast, | 1132 | .tweak = ov7670_t_contrast, |
1133 | .query = ov7670_q_contrast, | 1133 | .query = ov7670_q_contrast, |
1134 | }, | 1134 | }, |
1135 | { | 1135 | { |
1136 | .qc = { | 1136 | .qc = { |
1137 | .id = V4L2_CID_SATURATION, | 1137 | .id = V4L2_CID_SATURATION, |
1138 | .type = V4L2_CTRL_TYPE_INTEGER, | 1138 | .type = V4L2_CTRL_TYPE_INTEGER, |
1139 | .name = "Saturation", | 1139 | .name = "Saturation", |
1140 | .minimum = 0, | 1140 | .minimum = 0, |
1141 | .maximum = 256, | 1141 | .maximum = 256, |
1142 | .step = 1, | 1142 | .step = 1, |
1143 | .default_value = 0x80, | 1143 | .default_value = 0x80, |
1144 | .flags = V4L2_CTRL_FLAG_SLIDER | 1144 | .flags = V4L2_CTRL_FLAG_SLIDER |
1145 | }, | 1145 | }, |
1146 | .tweak = ov7670_t_sat, | 1146 | .tweak = ov7670_t_sat, |
1147 | .query = ov7670_q_sat, | 1147 | .query = ov7670_q_sat, |
1148 | }, | 1148 | }, |
1149 | { | 1149 | { |
1150 | .qc = { | 1150 | .qc = { |
1151 | .id = V4L2_CID_HUE, | 1151 | .id = V4L2_CID_HUE, |
1152 | .type = V4L2_CTRL_TYPE_INTEGER, | 1152 | .type = V4L2_CTRL_TYPE_INTEGER, |
1153 | .name = "HUE", | 1153 | .name = "HUE", |
1154 | .minimum = -180, | 1154 | .minimum = -180, |
1155 | .maximum = 180, | 1155 | .maximum = 180, |
1156 | .step = 5, | 1156 | .step = 5, |
1157 | .default_value = 0, | 1157 | .default_value = 0, |
1158 | .flags = V4L2_CTRL_FLAG_SLIDER | 1158 | .flags = V4L2_CTRL_FLAG_SLIDER |
1159 | }, | 1159 | }, |
1160 | .tweak = ov7670_t_hue, | 1160 | .tweak = ov7670_t_hue, |
1161 | .query = ov7670_q_hue, | 1161 | .query = ov7670_q_hue, |
1162 | }, | 1162 | }, |
1163 | { | 1163 | { |
1164 | .qc = { | 1164 | .qc = { |
1165 | .id = V4L2_CID_VFLIP, | 1165 | .id = V4L2_CID_VFLIP, |
1166 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 1166 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
1167 | .name = "Vertical flip", | 1167 | .name = "Vertical flip", |
1168 | .minimum = 0, | 1168 | .minimum = 0, |
1169 | .maximum = 1, | 1169 | .maximum = 1, |
1170 | .step = 1, | 1170 | .step = 1, |
1171 | .default_value = 0, | 1171 | .default_value = 0, |
1172 | }, | 1172 | }, |
1173 | .tweak = ov7670_t_vflip, | 1173 | .tweak = ov7670_t_vflip, |
1174 | .query = ov7670_q_vflip, | 1174 | .query = ov7670_q_vflip, |
1175 | }, | 1175 | }, |
1176 | { | 1176 | { |
1177 | .qc = { | 1177 | .qc = { |
1178 | .id = V4L2_CID_HFLIP, | 1178 | .id = V4L2_CID_HFLIP, |
1179 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 1179 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
1180 | .name = "Horizontal mirror", | 1180 | .name = "Horizontal mirror", |
1181 | .minimum = 0, | 1181 | .minimum = 0, |
1182 | .maximum = 1, | 1182 | .maximum = 1, |
1183 | .step = 1, | 1183 | .step = 1, |
1184 | .default_value = 0, | 1184 | .default_value = 0, |
1185 | }, | 1185 | }, |
1186 | .tweak = ov7670_t_hflip, | 1186 | .tweak = ov7670_t_hflip, |
1187 | .query = ov7670_q_hflip, | 1187 | .query = ov7670_q_hflip, |
1188 | }, | 1188 | }, |
1189 | }; | 1189 | }; |
1190 | #define N_CONTROLS (ARRAY_SIZE(ov7670_controls)) | 1190 | #define N_CONTROLS (ARRAY_SIZE(ov7670_controls)) |
1191 | 1191 | ||
1192 | static struct ov7670_control *ov7670_find_control(__u32 id) | 1192 | static struct ov7670_control *ov7670_find_control(__u32 id) |
1193 | { | 1193 | { |
1194 | int i; | 1194 | int i; |
1195 | 1195 | ||
1196 | for (i = 0; i < N_CONTROLS; i++) | 1196 | for (i = 0; i < N_CONTROLS; i++) |
1197 | if (ov7670_controls[i].qc.id == id) | 1197 | if (ov7670_controls[i].qc.id == id) |
1198 | return ov7670_controls + i; | 1198 | return ov7670_controls + i; |
1199 | return NULL; | 1199 | return NULL; |
1200 | } | 1200 | } |
1201 | 1201 | ||
1202 | 1202 | ||
1203 | static int ov7670_queryctrl(struct i2c_client *client, | 1203 | static int ov7670_queryctrl(struct i2c_client *client, |
1204 | struct v4l2_queryctrl *qc) | 1204 | struct v4l2_queryctrl *qc) |
1205 | { | 1205 | { |
1206 | struct ov7670_control *ctrl = ov7670_find_control(qc->id); | 1206 | struct ov7670_control *ctrl = ov7670_find_control(qc->id); |
1207 | 1207 | ||
1208 | if (ctrl == NULL) | 1208 | if (ctrl == NULL) |
1209 | return -EINVAL; | 1209 | return -EINVAL; |
1210 | *qc = ctrl->qc; | 1210 | *qc = ctrl->qc; |
1211 | return 0; | 1211 | return 0; |
1212 | } | 1212 | } |
1213 | 1213 | ||
1214 | static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 1214 | static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) |
1215 | { | 1215 | { |
1216 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); | 1216 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); |
1217 | int ret; | 1217 | int ret; |
1218 | 1218 | ||
1219 | if (octrl == NULL) | 1219 | if (octrl == NULL) |
1220 | return -EINVAL; | 1220 | return -EINVAL; |
1221 | ret = octrl->query(client, &ctrl->value); | 1221 | ret = octrl->query(client, &ctrl->value); |
1222 | if (ret >= 0) | 1222 | if (ret >= 0) |
1223 | return 0; | 1223 | return 0; |
1224 | return ret; | 1224 | return ret; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 1227 | static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) |
1228 | { | 1228 | { |
1229 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); | 1229 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); |
1230 | int ret; | 1230 | int ret; |
1231 | 1231 | ||
1232 | if (octrl == NULL) | 1232 | if (octrl == NULL) |
1233 | return -EINVAL; | 1233 | return -EINVAL; |
1234 | ret = octrl->tweak(client, ctrl->value); | 1234 | ret = octrl->tweak(client, ctrl->value); |
1235 | if (ret >= 0) | 1235 | if (ret >= 0) |
1236 | return 0; | 1236 | return 0; |
1237 | return ret; | 1237 | return ret; |
1238 | } | 1238 | } |
1239 | 1239 | ||
1240 | 1240 | ||
1241 | 1241 | ||
1242 | 1242 | ||
1243 | 1243 | ||
1244 | 1244 | ||
1245 | /* | 1245 | /* |
1246 | * Basic i2c stuff. | 1246 | * Basic i2c stuff. |
1247 | */ | 1247 | */ |
1248 | static struct i2c_driver ov7670_driver; | 1248 | static struct i2c_driver ov7670_driver; |
1249 | 1249 | ||
1250 | static int ov7670_attach(struct i2c_adapter *adapter) | 1250 | static int ov7670_attach(struct i2c_adapter *adapter) |
1251 | { | 1251 | { |
1252 | int ret; | 1252 | int ret; |
1253 | struct i2c_client *client; | 1253 | struct i2c_client *client; |
1254 | struct ov7670_info *info; | 1254 | struct ov7670_info *info; |
1255 | 1255 | ||
1256 | /* | 1256 | /* |
1257 | * For now: only deal with adapters we recognize. | 1257 | * For now: only deal with adapters we recognize. |
1258 | */ | 1258 | */ |
1259 | if (adapter->id != I2C_HW_SMBUS_CAFE) | 1259 | if (adapter->id != I2C_HW_SMBUS_CAFE) |
1260 | return -ENODEV; | 1260 | return -ENODEV; |
1261 | 1261 | ||
1262 | client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); | 1262 | client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); |
1263 | if (! client) | 1263 | if (! client) |
1264 | return -ENOMEM; | 1264 | return -ENOMEM; |
1265 | client->adapter = adapter; | 1265 | client->adapter = adapter; |
1266 | client->addr = OV7670_I2C_ADDR; | 1266 | client->addr = OV7670_I2C_ADDR; |
1267 | client->driver = &ov7670_driver, | 1267 | client->driver = &ov7670_driver, |
1268 | strcpy(client->name, "OV7670"); | 1268 | strcpy(client->name, "OV7670"); |
1269 | /* | 1269 | /* |
1270 | * Set up our info structure. | 1270 | * Set up our info structure. |
1271 | */ | 1271 | */ |
1272 | info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); | 1272 | info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); |
1273 | if (! info) { | 1273 | if (! info) { |
1274 | ret = -ENOMEM; | 1274 | ret = -ENOMEM; |
1275 | goto out_free; | 1275 | goto out_free; |
1276 | } | 1276 | } |
1277 | info->fmt = &ov7670_formats[0]; | 1277 | info->fmt = &ov7670_formats[0]; |
1278 | info->sat = 128; /* Review this */ | 1278 | info->sat = 128; /* Review this */ |
1279 | i2c_set_clientdata(client, info); | 1279 | i2c_set_clientdata(client, info); |
1280 | 1280 | ||
1281 | /* | 1281 | /* |
1282 | * Make sure it's an ov7670 | 1282 | * Make sure it's an ov7670 |
1283 | */ | 1283 | */ |
1284 | ret = ov7670_detect(client); | 1284 | ret = ov7670_detect(client); |
1285 | if (ret) | 1285 | if (ret) |
1286 | goto out_free_info; | 1286 | goto out_free_info; |
1287 | ret = i2c_attach_client(client); | 1287 | ret = i2c_attach_client(client); |
1288 | if (ret) | 1288 | if (ret) |
1289 | goto out_free_info; | 1289 | goto out_free_info; |
1290 | return 0; | 1290 | return 0; |
1291 | 1291 | ||
1292 | out_free_info: | 1292 | out_free_info: |
1293 | kfree(info); | 1293 | kfree(info); |
1294 | out_free: | 1294 | out_free: |
1295 | kfree(client); | 1295 | kfree(client); |
1296 | return ret; | 1296 | return ret; |
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | 1299 | ||
1300 | static int ov7670_detach(struct i2c_client *client) | 1300 | static int ov7670_detach(struct i2c_client *client) |
1301 | { | 1301 | { |
1302 | i2c_detach_client(client); | 1302 | i2c_detach_client(client); |
1303 | kfree(i2c_get_clientdata(client)); | 1303 | kfree(i2c_get_clientdata(client)); |
1304 | kfree(client); | 1304 | kfree(client); |
1305 | return 0; | 1305 | return 0; |
1306 | } | 1306 | } |
1307 | 1307 | ||
1308 | 1308 | ||
1309 | static int ov7670_command(struct i2c_client *client, unsigned int cmd, | 1309 | static int ov7670_command(struct i2c_client *client, unsigned int cmd, |
1310 | void *arg) | 1310 | void *arg) |
1311 | { | 1311 | { |
1312 | switch (cmd) { | 1312 | switch (cmd) { |
1313 | case VIDIOC_DBG_G_CHIP_IDENT: | 1313 | case VIDIOC_DBG_G_CHIP_IDENT: |
1314 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); | 1314 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); |
1315 | 1315 | ||
1316 | case VIDIOC_INT_RESET: | 1316 | case VIDIOC_INT_RESET: |
1317 | ov7670_reset(client); | 1317 | ov7670_reset(client); |
1318 | return 0; | 1318 | return 0; |
1319 | 1319 | ||
1320 | case VIDIOC_INT_INIT: | 1320 | case VIDIOC_INT_INIT: |
1321 | return ov7670_init(client); | 1321 | return ov7670_init(client); |
1322 | 1322 | ||
1323 | case VIDIOC_ENUM_FMT: | 1323 | case VIDIOC_ENUM_FMT: |
1324 | return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); | 1324 | return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); |
1325 | case VIDIOC_TRY_FMT: | 1325 | case VIDIOC_TRY_FMT: |
1326 | return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); | 1326 | return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); |
1327 | case VIDIOC_S_FMT: | 1327 | case VIDIOC_S_FMT: |
1328 | return ov7670_s_fmt(client, (struct v4l2_format *) arg); | 1328 | return ov7670_s_fmt(client, (struct v4l2_format *) arg); |
1329 | case VIDIOC_QUERYCTRL: | 1329 | case VIDIOC_QUERYCTRL: |
1330 | return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); | 1330 | return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); |
1331 | case VIDIOC_S_CTRL: | 1331 | case VIDIOC_S_CTRL: |
1332 | return ov7670_s_ctrl(client, (struct v4l2_control *) arg); | 1332 | return ov7670_s_ctrl(client, (struct v4l2_control *) arg); |
1333 | case VIDIOC_G_CTRL: | 1333 | case VIDIOC_G_CTRL: |
1334 | return ov7670_g_ctrl(client, (struct v4l2_control *) arg); | 1334 | return ov7670_g_ctrl(client, (struct v4l2_control *) arg); |
1335 | case VIDIOC_S_PARM: | 1335 | case VIDIOC_S_PARM: |
1336 | return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); | 1336 | return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); |
1337 | case VIDIOC_G_PARM: | 1337 | case VIDIOC_G_PARM: |
1338 | return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); | 1338 | return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); |
1339 | } | 1339 | } |
1340 | return -EINVAL; | 1340 | return -EINVAL; |
1341 | } | 1341 | } |
1342 | 1342 | ||
1343 | 1343 | ||
1344 | 1344 | ||
1345 | static struct i2c_driver ov7670_driver = { | 1345 | static struct i2c_driver ov7670_driver = { |
1346 | .driver = { | 1346 | .driver = { |
1347 | .name = "ov7670", | 1347 | .name = "ov7670", |
1348 | }, | 1348 | }, |
1349 | .id = I2C_DRIVERID_OV7670, | 1349 | .id = I2C_DRIVERID_OV7670, |
1350 | .attach_adapter = ov7670_attach, | 1350 | .attach_adapter = ov7670_attach, |
1351 | .detach_client = ov7670_detach, | 1351 | .detach_client = ov7670_detach, |
1352 | .command = ov7670_command, | 1352 | .command = ov7670_command, |
1353 | }; | 1353 | }; |
1354 | 1354 | ||
1355 | 1355 | ||
1356 | /* | 1356 | /* |
1357 | * Module initialization | 1357 | * Module initialization |
1358 | */ | 1358 | */ |
1359 | static int __init ov7670_mod_init(void) | 1359 | static int __init ov7670_mod_init(void) |
1360 | { | 1360 | { |
1361 | printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); | 1361 | printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); |
1362 | return i2c_add_driver(&ov7670_driver); | 1362 | return i2c_add_driver(&ov7670_driver); |
1363 | } | 1363 | } |
1364 | 1364 | ||
1365 | static void __exit ov7670_mod_exit(void) | 1365 | static void __exit ov7670_mod_exit(void) |
1366 | { | 1366 | { |
1367 | i2c_del_driver(&ov7670_driver); | 1367 | i2c_del_driver(&ov7670_driver); |
1368 | } | 1368 | } |
1369 | 1369 | ||
1370 | module_init(ov7670_mod_init); | 1370 | module_init(ov7670_mod_init); |
1371 | module_exit(ov7670_mod_exit); | 1371 | module_exit(ov7670_mod_exit); |
1372 | 1372 |
drivers/media/video/saa7134/saa7134-video.c
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * device driver for philips saa7134 based TV cards | 3 | * device driver for philips saa7134 based TV cards |
4 | * video4linux video interface | 4 | * video4linux video interface |
5 | * | 5 | * |
6 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | 6 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/sort.h> | 28 | #include <linux/sort.h> |
29 | 29 | ||
30 | #include "saa7134-reg.h" | 30 | #include "saa7134-reg.h" |
31 | #include "saa7134.h" | 31 | #include "saa7134.h" |
32 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
33 | 33 | ||
34 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
35 | /* Include V4L1 specific functions. Should be removed soon */ | ||
36 | #include <linux/videodev.h> | ||
37 | #endif | ||
38 | |||
39 | /* ------------------------------------------------------------------ */ | 34 | /* ------------------------------------------------------------------ */ |
40 | 35 | ||
41 | unsigned int video_debug; | 36 | unsigned int video_debug; |
42 | static unsigned int gbuffers = 8; | 37 | static unsigned int gbuffers = 8; |
43 | static unsigned int noninterlaced; /* 0 */ | 38 | static unsigned int noninterlaced; /* 0 */ |
44 | static unsigned int gbufsize = 720*576*4; | 39 | static unsigned int gbufsize = 720*576*4; |
45 | static unsigned int gbufsize_max = 720*576*4; | 40 | static unsigned int gbufsize_max = 720*576*4; |
46 | static char secam[] = "--"; | 41 | static char secam[] = "--"; |
47 | module_param(video_debug, int, 0644); | 42 | module_param(video_debug, int, 0644); |
48 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); | 43 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); |
49 | module_param(gbuffers, int, 0444); | 44 | module_param(gbuffers, int, 0444); |
50 | MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); | 45 | MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); |
51 | module_param(noninterlaced, int, 0644); | 46 | module_param(noninterlaced, int, 0644); |
52 | MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); | 47 | MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); |
53 | module_param_string(secam, secam, sizeof(secam), 0644); | 48 | module_param_string(secam, secam, sizeof(secam), 0644); |
54 | MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); | 49 | MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); |
55 | 50 | ||
56 | 51 | ||
57 | #define dprintk(fmt, arg...) if (video_debug&0x04) \ | 52 | #define dprintk(fmt, arg...) if (video_debug&0x04) \ |
58 | printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) | 53 | printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) |
59 | 54 | ||
60 | /* ------------------------------------------------------------------ */ | 55 | /* ------------------------------------------------------------------ */ |
61 | /* Defines for Video Output Port Register at address 0x191 */ | 56 | /* Defines for Video Output Port Register at address 0x191 */ |
62 | 57 | ||
63 | /* Bit 0: VIP code T bit polarity */ | 58 | /* Bit 0: VIP code T bit polarity */ |
64 | 59 | ||
65 | #define VP_T_CODE_P_NON_INVERTED 0x00 | 60 | #define VP_T_CODE_P_NON_INVERTED 0x00 |
66 | #define VP_T_CODE_P_INVERTED 0x01 | 61 | #define VP_T_CODE_P_INVERTED 0x01 |
67 | 62 | ||
68 | /* ------------------------------------------------------------------ */ | 63 | /* ------------------------------------------------------------------ */ |
69 | /* Defines for Video Output Port Register at address 0x195 */ | 64 | /* Defines for Video Output Port Register at address 0x195 */ |
70 | 65 | ||
71 | /* Bit 2: Video output clock delay control */ | 66 | /* Bit 2: Video output clock delay control */ |
72 | 67 | ||
73 | #define VP_CLK_CTRL2_NOT_DELAYED 0x00 | 68 | #define VP_CLK_CTRL2_NOT_DELAYED 0x00 |
74 | #define VP_CLK_CTRL2_DELAYED 0x04 | 69 | #define VP_CLK_CTRL2_DELAYED 0x04 |
75 | 70 | ||
76 | /* Bit 1: Video output clock invert control */ | 71 | /* Bit 1: Video output clock invert control */ |
77 | 72 | ||
78 | #define VP_CLK_CTRL1_NON_INVERTED 0x00 | 73 | #define VP_CLK_CTRL1_NON_INVERTED 0x00 |
79 | #define VP_CLK_CTRL1_INVERTED 0x02 | 74 | #define VP_CLK_CTRL1_INVERTED 0x02 |
80 | 75 | ||
81 | /* ------------------------------------------------------------------ */ | 76 | /* ------------------------------------------------------------------ */ |
82 | /* Defines for Video Output Port Register at address 0x196 */ | 77 | /* Defines for Video Output Port Register at address 0x196 */ |
83 | 78 | ||
84 | /* Bits 2 to 0: VSYNC pin video vertical sync type */ | 79 | /* Bits 2 to 0: VSYNC pin video vertical sync type */ |
85 | 80 | ||
86 | #define VP_VS_TYPE_MASK 0x07 | 81 | #define VP_VS_TYPE_MASK 0x07 |
87 | 82 | ||
88 | #define VP_VS_TYPE_OFF 0x00 | 83 | #define VP_VS_TYPE_OFF 0x00 |
89 | #define VP_VS_TYPE_V123 0x01 | 84 | #define VP_VS_TYPE_V123 0x01 |
90 | #define VP_VS_TYPE_V_ITU 0x02 | 85 | #define VP_VS_TYPE_V_ITU 0x02 |
91 | #define VP_VS_TYPE_VGATE_L 0x03 | 86 | #define VP_VS_TYPE_VGATE_L 0x03 |
92 | #define VP_VS_TYPE_RESERVED1 0x04 | 87 | #define VP_VS_TYPE_RESERVED1 0x04 |
93 | #define VP_VS_TYPE_RESERVED2 0x05 | 88 | #define VP_VS_TYPE_RESERVED2 0x05 |
94 | #define VP_VS_TYPE_F_ITU 0x06 | 89 | #define VP_VS_TYPE_F_ITU 0x06 |
95 | #define VP_VS_TYPE_SC_FID 0x07 | 90 | #define VP_VS_TYPE_SC_FID 0x07 |
96 | 91 | ||
97 | /* ------------------------------------------------------------------ */ | 92 | /* ------------------------------------------------------------------ */ |
98 | /* data structs for video */ | 93 | /* data structs for video */ |
99 | 94 | ||
100 | static int video_out[][9] = { | 95 | static int video_out[][9] = { |
101 | [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, | 96 | [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, |
102 | }; | 97 | }; |
103 | 98 | ||
104 | static struct saa7134_format formats[] = { | 99 | static struct saa7134_format formats[] = { |
105 | { | 100 | { |
106 | .name = "8 bpp gray", | 101 | .name = "8 bpp gray", |
107 | .fourcc = V4L2_PIX_FMT_GREY, | 102 | .fourcc = V4L2_PIX_FMT_GREY, |
108 | .depth = 8, | 103 | .depth = 8, |
109 | .pm = 0x06, | 104 | .pm = 0x06, |
110 | },{ | 105 | },{ |
111 | .name = "15 bpp RGB, le", | 106 | .name = "15 bpp RGB, le", |
112 | .fourcc = V4L2_PIX_FMT_RGB555, | 107 | .fourcc = V4L2_PIX_FMT_RGB555, |
113 | .depth = 16, | 108 | .depth = 16, |
114 | .pm = 0x13 | 0x80, | 109 | .pm = 0x13 | 0x80, |
115 | },{ | 110 | },{ |
116 | .name = "15 bpp RGB, be", | 111 | .name = "15 bpp RGB, be", |
117 | .fourcc = V4L2_PIX_FMT_RGB555X, | 112 | .fourcc = V4L2_PIX_FMT_RGB555X, |
118 | .depth = 16, | 113 | .depth = 16, |
119 | .pm = 0x13 | 0x80, | 114 | .pm = 0x13 | 0x80, |
120 | .bswap = 1, | 115 | .bswap = 1, |
121 | },{ | 116 | },{ |
122 | .name = "16 bpp RGB, le", | 117 | .name = "16 bpp RGB, le", |
123 | .fourcc = V4L2_PIX_FMT_RGB565, | 118 | .fourcc = V4L2_PIX_FMT_RGB565, |
124 | .depth = 16, | 119 | .depth = 16, |
125 | .pm = 0x10 | 0x80, | 120 | .pm = 0x10 | 0x80, |
126 | },{ | 121 | },{ |
127 | .name = "16 bpp RGB, be", | 122 | .name = "16 bpp RGB, be", |
128 | .fourcc = V4L2_PIX_FMT_RGB565X, | 123 | .fourcc = V4L2_PIX_FMT_RGB565X, |
129 | .depth = 16, | 124 | .depth = 16, |
130 | .pm = 0x10 | 0x80, | 125 | .pm = 0x10 | 0x80, |
131 | .bswap = 1, | 126 | .bswap = 1, |
132 | },{ | 127 | },{ |
133 | .name = "24 bpp RGB, le", | 128 | .name = "24 bpp RGB, le", |
134 | .fourcc = V4L2_PIX_FMT_BGR24, | 129 | .fourcc = V4L2_PIX_FMT_BGR24, |
135 | .depth = 24, | 130 | .depth = 24, |
136 | .pm = 0x11, | 131 | .pm = 0x11, |
137 | },{ | 132 | },{ |
138 | .name = "24 bpp RGB, be", | 133 | .name = "24 bpp RGB, be", |
139 | .fourcc = V4L2_PIX_FMT_RGB24, | 134 | .fourcc = V4L2_PIX_FMT_RGB24, |
140 | .depth = 24, | 135 | .depth = 24, |
141 | .pm = 0x11, | 136 | .pm = 0x11, |
142 | .bswap = 1, | 137 | .bswap = 1, |
143 | },{ | 138 | },{ |
144 | .name = "32 bpp RGB, le", | 139 | .name = "32 bpp RGB, le", |
145 | .fourcc = V4L2_PIX_FMT_BGR32, | 140 | .fourcc = V4L2_PIX_FMT_BGR32, |
146 | .depth = 32, | 141 | .depth = 32, |
147 | .pm = 0x12, | 142 | .pm = 0x12, |
148 | },{ | 143 | },{ |
149 | .name = "32 bpp RGB, be", | 144 | .name = "32 bpp RGB, be", |
150 | .fourcc = V4L2_PIX_FMT_RGB32, | 145 | .fourcc = V4L2_PIX_FMT_RGB32, |
151 | .depth = 32, | 146 | .depth = 32, |
152 | .pm = 0x12, | 147 | .pm = 0x12, |
153 | .bswap = 1, | 148 | .bswap = 1, |
154 | .wswap = 1, | 149 | .wswap = 1, |
155 | },{ | 150 | },{ |
156 | .name = "4:2:2 packed, YUYV", | 151 | .name = "4:2:2 packed, YUYV", |
157 | .fourcc = V4L2_PIX_FMT_YUYV, | 152 | .fourcc = V4L2_PIX_FMT_YUYV, |
158 | .depth = 16, | 153 | .depth = 16, |
159 | .pm = 0x00, | 154 | .pm = 0x00, |
160 | .bswap = 1, | 155 | .bswap = 1, |
161 | .yuv = 1, | 156 | .yuv = 1, |
162 | },{ | 157 | },{ |
163 | .name = "4:2:2 packed, UYVY", | 158 | .name = "4:2:2 packed, UYVY", |
164 | .fourcc = V4L2_PIX_FMT_UYVY, | 159 | .fourcc = V4L2_PIX_FMT_UYVY, |
165 | .depth = 16, | 160 | .depth = 16, |
166 | .pm = 0x00, | 161 | .pm = 0x00, |
167 | .yuv = 1, | 162 | .yuv = 1, |
168 | },{ | 163 | },{ |
169 | .name = "4:2:2 planar, Y-Cb-Cr", | 164 | .name = "4:2:2 planar, Y-Cb-Cr", |
170 | .fourcc = V4L2_PIX_FMT_YUV422P, | 165 | .fourcc = V4L2_PIX_FMT_YUV422P, |
171 | .depth = 16, | 166 | .depth = 16, |
172 | .pm = 0x09, | 167 | .pm = 0x09, |
173 | .yuv = 1, | 168 | .yuv = 1, |
174 | .planar = 1, | 169 | .planar = 1, |
175 | .hshift = 1, | 170 | .hshift = 1, |
176 | .vshift = 0, | 171 | .vshift = 0, |
177 | },{ | 172 | },{ |
178 | .name = "4:2:0 planar, Y-Cb-Cr", | 173 | .name = "4:2:0 planar, Y-Cb-Cr", |
179 | .fourcc = V4L2_PIX_FMT_YUV420, | 174 | .fourcc = V4L2_PIX_FMT_YUV420, |
180 | .depth = 12, | 175 | .depth = 12, |
181 | .pm = 0x0a, | 176 | .pm = 0x0a, |
182 | .yuv = 1, | 177 | .yuv = 1, |
183 | .planar = 1, | 178 | .planar = 1, |
184 | .hshift = 1, | 179 | .hshift = 1, |
185 | .vshift = 1, | 180 | .vshift = 1, |
186 | },{ | 181 | },{ |
187 | .name = "4:2:0 planar, Y-Cb-Cr", | 182 | .name = "4:2:0 planar, Y-Cb-Cr", |
188 | .fourcc = V4L2_PIX_FMT_YVU420, | 183 | .fourcc = V4L2_PIX_FMT_YVU420, |
189 | .depth = 12, | 184 | .depth = 12, |
190 | .pm = 0x0a, | 185 | .pm = 0x0a, |
191 | .yuv = 1, | 186 | .yuv = 1, |
192 | .planar = 1, | 187 | .planar = 1, |
193 | .uvswap = 1, | 188 | .uvswap = 1, |
194 | .hshift = 1, | 189 | .hshift = 1, |
195 | .vshift = 1, | 190 | .vshift = 1, |
196 | } | 191 | } |
197 | }; | 192 | }; |
198 | #define FORMATS ARRAY_SIZE(formats) | 193 | #define FORMATS ARRAY_SIZE(formats) |
199 | 194 | ||
200 | #define NORM_625_50 \ | 195 | #define NORM_625_50 \ |
201 | .h_start = 0, \ | 196 | .h_start = 0, \ |
202 | .h_stop = 719, \ | 197 | .h_stop = 719, \ |
203 | .video_v_start = 24, \ | 198 | .video_v_start = 24, \ |
204 | .video_v_stop = 311, \ | 199 | .video_v_stop = 311, \ |
205 | .vbi_v_start_0 = 7, \ | 200 | .vbi_v_start_0 = 7, \ |
206 | .vbi_v_stop_0 = 22, \ | 201 | .vbi_v_stop_0 = 22, \ |
207 | .vbi_v_start_1 = 319, \ | 202 | .vbi_v_start_1 = 319, \ |
208 | .src_timing = 4 | 203 | .src_timing = 4 |
209 | 204 | ||
210 | #define NORM_525_60 \ | 205 | #define NORM_525_60 \ |
211 | .h_start = 0, \ | 206 | .h_start = 0, \ |
212 | .h_stop = 703, \ | 207 | .h_stop = 703, \ |
213 | .video_v_start = 23, \ | 208 | .video_v_start = 23, \ |
214 | .video_v_stop = 262, \ | 209 | .video_v_stop = 262, \ |
215 | .vbi_v_start_0 = 10, \ | 210 | .vbi_v_start_0 = 10, \ |
216 | .vbi_v_stop_0 = 21, \ | 211 | .vbi_v_stop_0 = 21, \ |
217 | .vbi_v_start_1 = 273, \ | 212 | .vbi_v_start_1 = 273, \ |
218 | .src_timing = 7 | 213 | .src_timing = 7 |
219 | 214 | ||
220 | static struct saa7134_tvnorm tvnorms[] = { | 215 | static struct saa7134_tvnorm tvnorms[] = { |
221 | { | 216 | { |
222 | .name = "PAL", /* autodetect */ | 217 | .name = "PAL", /* autodetect */ |
223 | .id = V4L2_STD_PAL, | 218 | .id = V4L2_STD_PAL, |
224 | NORM_625_50, | 219 | NORM_625_50, |
225 | 220 | ||
226 | .sync_control = 0x18, | 221 | .sync_control = 0x18, |
227 | .luma_control = 0x40, | 222 | .luma_control = 0x40, |
228 | .chroma_ctrl1 = 0x81, | 223 | .chroma_ctrl1 = 0x81, |
229 | .chroma_gain = 0x2a, | 224 | .chroma_gain = 0x2a, |
230 | .chroma_ctrl2 = 0x06, | 225 | .chroma_ctrl2 = 0x06, |
231 | .vgate_misc = 0x1c, | 226 | .vgate_misc = 0x1c, |
232 | 227 | ||
233 | },{ | 228 | },{ |
234 | .name = "PAL-BG", | 229 | .name = "PAL-BG", |
235 | .id = V4L2_STD_PAL_BG, | 230 | .id = V4L2_STD_PAL_BG, |
236 | NORM_625_50, | 231 | NORM_625_50, |
237 | 232 | ||
238 | .sync_control = 0x18, | 233 | .sync_control = 0x18, |
239 | .luma_control = 0x40, | 234 | .luma_control = 0x40, |
240 | .chroma_ctrl1 = 0x81, | 235 | .chroma_ctrl1 = 0x81, |
241 | .chroma_gain = 0x2a, | 236 | .chroma_gain = 0x2a, |
242 | .chroma_ctrl2 = 0x06, | 237 | .chroma_ctrl2 = 0x06, |
243 | .vgate_misc = 0x1c, | 238 | .vgate_misc = 0x1c, |
244 | 239 | ||
245 | },{ | 240 | },{ |
246 | .name = "PAL-I", | 241 | .name = "PAL-I", |
247 | .id = V4L2_STD_PAL_I, | 242 | .id = V4L2_STD_PAL_I, |
248 | NORM_625_50, | 243 | NORM_625_50, |
249 | 244 | ||
250 | .sync_control = 0x18, | 245 | .sync_control = 0x18, |
251 | .luma_control = 0x40, | 246 | .luma_control = 0x40, |
252 | .chroma_ctrl1 = 0x81, | 247 | .chroma_ctrl1 = 0x81, |
253 | .chroma_gain = 0x2a, | 248 | .chroma_gain = 0x2a, |
254 | .chroma_ctrl2 = 0x06, | 249 | .chroma_ctrl2 = 0x06, |
255 | .vgate_misc = 0x1c, | 250 | .vgate_misc = 0x1c, |
256 | 251 | ||
257 | },{ | 252 | },{ |
258 | .name = "PAL-DK", | 253 | .name = "PAL-DK", |
259 | .id = V4L2_STD_PAL_DK, | 254 | .id = V4L2_STD_PAL_DK, |
260 | NORM_625_50, | 255 | NORM_625_50, |
261 | 256 | ||
262 | .sync_control = 0x18, | 257 | .sync_control = 0x18, |
263 | .luma_control = 0x40, | 258 | .luma_control = 0x40, |
264 | .chroma_ctrl1 = 0x81, | 259 | .chroma_ctrl1 = 0x81, |
265 | .chroma_gain = 0x2a, | 260 | .chroma_gain = 0x2a, |
266 | .chroma_ctrl2 = 0x06, | 261 | .chroma_ctrl2 = 0x06, |
267 | .vgate_misc = 0x1c, | 262 | .vgate_misc = 0x1c, |
268 | 263 | ||
269 | },{ | 264 | },{ |
270 | .name = "NTSC", | 265 | .name = "NTSC", |
271 | .id = V4L2_STD_NTSC, | 266 | .id = V4L2_STD_NTSC, |
272 | NORM_525_60, | 267 | NORM_525_60, |
273 | 268 | ||
274 | .sync_control = 0x59, | 269 | .sync_control = 0x59, |
275 | .luma_control = 0x40, | 270 | .luma_control = 0x40, |
276 | .chroma_ctrl1 = 0x89, | 271 | .chroma_ctrl1 = 0x89, |
277 | .chroma_gain = 0x2a, | 272 | .chroma_gain = 0x2a, |
278 | .chroma_ctrl2 = 0x0e, | 273 | .chroma_ctrl2 = 0x0e, |
279 | .vgate_misc = 0x18, | 274 | .vgate_misc = 0x18, |
280 | 275 | ||
281 | },{ | 276 | },{ |
282 | .name = "SECAM", | 277 | .name = "SECAM", |
283 | .id = V4L2_STD_SECAM, | 278 | .id = V4L2_STD_SECAM, |
284 | NORM_625_50, | 279 | NORM_625_50, |
285 | 280 | ||
286 | .sync_control = 0x18, | 281 | .sync_control = 0x18, |
287 | .luma_control = 0x1b, | 282 | .luma_control = 0x1b, |
288 | .chroma_ctrl1 = 0xd1, | 283 | .chroma_ctrl1 = 0xd1, |
289 | .chroma_gain = 0x80, | 284 | .chroma_gain = 0x80, |
290 | .chroma_ctrl2 = 0x00, | 285 | .chroma_ctrl2 = 0x00, |
291 | .vgate_misc = 0x1c, | 286 | .vgate_misc = 0x1c, |
292 | 287 | ||
293 | },{ | 288 | },{ |
294 | .name = "SECAM-DK", | 289 | .name = "SECAM-DK", |
295 | .id = V4L2_STD_SECAM_DK, | 290 | .id = V4L2_STD_SECAM_DK, |
296 | NORM_625_50, | 291 | NORM_625_50, |
297 | 292 | ||
298 | .sync_control = 0x18, | 293 | .sync_control = 0x18, |
299 | .luma_control = 0x1b, | 294 | .luma_control = 0x1b, |
300 | .chroma_ctrl1 = 0xd1, | 295 | .chroma_ctrl1 = 0xd1, |
301 | .chroma_gain = 0x80, | 296 | .chroma_gain = 0x80, |
302 | .chroma_ctrl2 = 0x00, | 297 | .chroma_ctrl2 = 0x00, |
303 | .vgate_misc = 0x1c, | 298 | .vgate_misc = 0x1c, |
304 | 299 | ||
305 | },{ | 300 | },{ |
306 | .name = "SECAM-L", | 301 | .name = "SECAM-L", |
307 | .id = V4L2_STD_SECAM_L, | 302 | .id = V4L2_STD_SECAM_L, |
308 | NORM_625_50, | 303 | NORM_625_50, |
309 | 304 | ||
310 | .sync_control = 0x18, | 305 | .sync_control = 0x18, |
311 | .luma_control = 0x1b, | 306 | .luma_control = 0x1b, |
312 | .chroma_ctrl1 = 0xd1, | 307 | .chroma_ctrl1 = 0xd1, |
313 | .chroma_gain = 0x80, | 308 | .chroma_gain = 0x80, |
314 | .chroma_ctrl2 = 0x00, | 309 | .chroma_ctrl2 = 0x00, |
315 | .vgate_misc = 0x1c, | 310 | .vgate_misc = 0x1c, |
316 | 311 | ||
317 | },{ | 312 | },{ |
318 | .name = "SECAM-Lc", | 313 | .name = "SECAM-Lc", |
319 | .id = V4L2_STD_SECAM_LC, | 314 | .id = V4L2_STD_SECAM_LC, |
320 | NORM_625_50, | 315 | NORM_625_50, |
321 | 316 | ||
322 | .sync_control = 0x18, | 317 | .sync_control = 0x18, |
323 | .luma_control = 0x1b, | 318 | .luma_control = 0x1b, |
324 | .chroma_ctrl1 = 0xd1, | 319 | .chroma_ctrl1 = 0xd1, |
325 | .chroma_gain = 0x80, | 320 | .chroma_gain = 0x80, |
326 | .chroma_ctrl2 = 0x00, | 321 | .chroma_ctrl2 = 0x00, |
327 | .vgate_misc = 0x1c, | 322 | .vgate_misc = 0x1c, |
328 | 323 | ||
329 | },{ | 324 | },{ |
330 | .name = "PAL-M", | 325 | .name = "PAL-M", |
331 | .id = V4L2_STD_PAL_M, | 326 | .id = V4L2_STD_PAL_M, |
332 | NORM_525_60, | 327 | NORM_525_60, |
333 | 328 | ||
334 | .sync_control = 0x59, | 329 | .sync_control = 0x59, |
335 | .luma_control = 0x40, | 330 | .luma_control = 0x40, |
336 | .chroma_ctrl1 = 0xb9, | 331 | .chroma_ctrl1 = 0xb9, |
337 | .chroma_gain = 0x2a, | 332 | .chroma_gain = 0x2a, |
338 | .chroma_ctrl2 = 0x0e, | 333 | .chroma_ctrl2 = 0x0e, |
339 | .vgate_misc = 0x18, | 334 | .vgate_misc = 0x18, |
340 | 335 | ||
341 | },{ | 336 | },{ |
342 | .name = "PAL-Nc", | 337 | .name = "PAL-Nc", |
343 | .id = V4L2_STD_PAL_Nc, | 338 | .id = V4L2_STD_PAL_Nc, |
344 | NORM_625_50, | 339 | NORM_625_50, |
345 | 340 | ||
346 | .sync_control = 0x18, | 341 | .sync_control = 0x18, |
347 | .luma_control = 0x40, | 342 | .luma_control = 0x40, |
348 | .chroma_ctrl1 = 0xa1, | 343 | .chroma_ctrl1 = 0xa1, |
349 | .chroma_gain = 0x2a, | 344 | .chroma_gain = 0x2a, |
350 | .chroma_ctrl2 = 0x06, | 345 | .chroma_ctrl2 = 0x06, |
351 | .vgate_misc = 0x1c, | 346 | .vgate_misc = 0x1c, |
352 | 347 | ||
353 | },{ | 348 | },{ |
354 | .name = "PAL-60", | 349 | .name = "PAL-60", |
355 | .id = V4L2_STD_PAL_60, | 350 | .id = V4L2_STD_PAL_60, |
356 | 351 | ||
357 | .h_start = 0, | 352 | .h_start = 0, |
358 | .h_stop = 719, | 353 | .h_stop = 719, |
359 | .video_v_start = 23, | 354 | .video_v_start = 23, |
360 | .video_v_stop = 262, | 355 | .video_v_stop = 262, |
361 | .vbi_v_start_0 = 10, | 356 | .vbi_v_start_0 = 10, |
362 | .vbi_v_stop_0 = 21, | 357 | .vbi_v_stop_0 = 21, |
363 | .vbi_v_start_1 = 273, | 358 | .vbi_v_start_1 = 273, |
364 | .src_timing = 7, | 359 | .src_timing = 7, |
365 | 360 | ||
366 | .sync_control = 0x18, | 361 | .sync_control = 0x18, |
367 | .luma_control = 0x40, | 362 | .luma_control = 0x40, |
368 | .chroma_ctrl1 = 0x81, | 363 | .chroma_ctrl1 = 0x81, |
369 | .chroma_gain = 0x2a, | 364 | .chroma_gain = 0x2a, |
370 | .chroma_ctrl2 = 0x06, | 365 | .chroma_ctrl2 = 0x06, |
371 | .vgate_misc = 0x1c, | 366 | .vgate_misc = 0x1c, |
372 | } | 367 | } |
373 | }; | 368 | }; |
374 | #define TVNORMS ARRAY_SIZE(tvnorms) | 369 | #define TVNORMS ARRAY_SIZE(tvnorms) |
375 | 370 | ||
376 | #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) | 371 | #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) |
377 | #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) | 372 | #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) |
378 | #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) | 373 | #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) |
379 | #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) | 374 | #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) |
380 | #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) | 375 | #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) |
381 | 376 | ||
382 | static const struct v4l2_queryctrl no_ctrl = { | 377 | static const struct v4l2_queryctrl no_ctrl = { |
383 | .name = "42", | 378 | .name = "42", |
384 | .flags = V4L2_CTRL_FLAG_DISABLED, | 379 | .flags = V4L2_CTRL_FLAG_DISABLED, |
385 | }; | 380 | }; |
386 | static const struct v4l2_queryctrl video_ctrls[] = { | 381 | static const struct v4l2_queryctrl video_ctrls[] = { |
387 | /* --- video --- */ | 382 | /* --- video --- */ |
388 | { | 383 | { |
389 | .id = V4L2_CID_BRIGHTNESS, | 384 | .id = V4L2_CID_BRIGHTNESS, |
390 | .name = "Brightness", | 385 | .name = "Brightness", |
391 | .minimum = 0, | 386 | .minimum = 0, |
392 | .maximum = 255, | 387 | .maximum = 255, |
393 | .step = 1, | 388 | .step = 1, |
394 | .default_value = 128, | 389 | .default_value = 128, |
395 | .type = V4L2_CTRL_TYPE_INTEGER, | 390 | .type = V4L2_CTRL_TYPE_INTEGER, |
396 | },{ | 391 | },{ |
397 | .id = V4L2_CID_CONTRAST, | 392 | .id = V4L2_CID_CONTRAST, |
398 | .name = "Contrast", | 393 | .name = "Contrast", |
399 | .minimum = 0, | 394 | .minimum = 0, |
400 | .maximum = 127, | 395 | .maximum = 127, |
401 | .step = 1, | 396 | .step = 1, |
402 | .default_value = 68, | 397 | .default_value = 68, |
403 | .type = V4L2_CTRL_TYPE_INTEGER, | 398 | .type = V4L2_CTRL_TYPE_INTEGER, |
404 | },{ | 399 | },{ |
405 | .id = V4L2_CID_SATURATION, | 400 | .id = V4L2_CID_SATURATION, |
406 | .name = "Saturation", | 401 | .name = "Saturation", |
407 | .minimum = 0, | 402 | .minimum = 0, |
408 | .maximum = 127, | 403 | .maximum = 127, |
409 | .step = 1, | 404 | .step = 1, |
410 | .default_value = 64, | 405 | .default_value = 64, |
411 | .type = V4L2_CTRL_TYPE_INTEGER, | 406 | .type = V4L2_CTRL_TYPE_INTEGER, |
412 | },{ | 407 | },{ |
413 | .id = V4L2_CID_HUE, | 408 | .id = V4L2_CID_HUE, |
414 | .name = "Hue", | 409 | .name = "Hue", |
415 | .minimum = -128, | 410 | .minimum = -128, |
416 | .maximum = 127, | 411 | .maximum = 127, |
417 | .step = 1, | 412 | .step = 1, |
418 | .default_value = 0, | 413 | .default_value = 0, |
419 | .type = V4L2_CTRL_TYPE_INTEGER, | 414 | .type = V4L2_CTRL_TYPE_INTEGER, |
420 | },{ | 415 | },{ |
421 | .id = V4L2_CID_HFLIP, | 416 | .id = V4L2_CID_HFLIP, |
422 | .name = "Mirror", | 417 | .name = "Mirror", |
423 | .minimum = 0, | 418 | .minimum = 0, |
424 | .maximum = 1, | 419 | .maximum = 1, |
425 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 420 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
426 | }, | 421 | }, |
427 | /* --- audio --- */ | 422 | /* --- audio --- */ |
428 | { | 423 | { |
429 | .id = V4L2_CID_AUDIO_MUTE, | 424 | .id = V4L2_CID_AUDIO_MUTE, |
430 | .name = "Mute", | 425 | .name = "Mute", |
431 | .minimum = 0, | 426 | .minimum = 0, |
432 | .maximum = 1, | 427 | .maximum = 1, |
433 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 428 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
434 | },{ | 429 | },{ |
435 | .id = V4L2_CID_AUDIO_VOLUME, | 430 | .id = V4L2_CID_AUDIO_VOLUME, |
436 | .name = "Volume", | 431 | .name = "Volume", |
437 | .minimum = -15, | 432 | .minimum = -15, |
438 | .maximum = 15, | 433 | .maximum = 15, |
439 | .step = 1, | 434 | .step = 1, |
440 | .default_value = 0, | 435 | .default_value = 0, |
441 | .type = V4L2_CTRL_TYPE_INTEGER, | 436 | .type = V4L2_CTRL_TYPE_INTEGER, |
442 | }, | 437 | }, |
443 | /* --- private --- */ | 438 | /* --- private --- */ |
444 | { | 439 | { |
445 | .id = V4L2_CID_PRIVATE_INVERT, | 440 | .id = V4L2_CID_PRIVATE_INVERT, |
446 | .name = "Invert", | 441 | .name = "Invert", |
447 | .minimum = 0, | 442 | .minimum = 0, |
448 | .maximum = 1, | 443 | .maximum = 1, |
449 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 444 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
450 | },{ | 445 | },{ |
451 | .id = V4L2_CID_PRIVATE_Y_ODD, | 446 | .id = V4L2_CID_PRIVATE_Y_ODD, |
452 | .name = "y offset odd field", | 447 | .name = "y offset odd field", |
453 | .minimum = 0, | 448 | .minimum = 0, |
454 | .maximum = 128, | 449 | .maximum = 128, |
455 | .step = 1, | 450 | .step = 1, |
456 | .default_value = 0, | 451 | .default_value = 0, |
457 | .type = V4L2_CTRL_TYPE_INTEGER, | 452 | .type = V4L2_CTRL_TYPE_INTEGER, |
458 | },{ | 453 | },{ |
459 | .id = V4L2_CID_PRIVATE_Y_EVEN, | 454 | .id = V4L2_CID_PRIVATE_Y_EVEN, |
460 | .name = "y offset even field", | 455 | .name = "y offset even field", |
461 | .minimum = 0, | 456 | .minimum = 0, |
462 | .maximum = 128, | 457 | .maximum = 128, |
463 | .step = 1, | 458 | .step = 1, |
464 | .default_value = 0, | 459 | .default_value = 0, |
465 | .type = V4L2_CTRL_TYPE_INTEGER, | 460 | .type = V4L2_CTRL_TYPE_INTEGER, |
466 | },{ | 461 | },{ |
467 | .id = V4L2_CID_PRIVATE_AUTOMUTE, | 462 | .id = V4L2_CID_PRIVATE_AUTOMUTE, |
468 | .name = "automute", | 463 | .name = "automute", |
469 | .minimum = 0, | 464 | .minimum = 0, |
470 | .maximum = 1, | 465 | .maximum = 1, |
471 | .default_value = 1, | 466 | .default_value = 1, |
472 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 467 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
473 | } | 468 | } |
474 | }; | 469 | }; |
475 | static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); | 470 | static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); |
476 | 471 | ||
477 | static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) | 472 | static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) |
478 | { | 473 | { |
479 | unsigned int i; | 474 | unsigned int i; |
480 | 475 | ||
481 | for (i = 0; i < CTRLS; i++) | 476 | for (i = 0; i < CTRLS; i++) |
482 | if (video_ctrls[i].id == id) | 477 | if (video_ctrls[i].id == id) |
483 | return video_ctrls+i; | 478 | return video_ctrls+i; |
484 | return NULL; | 479 | return NULL; |
485 | } | 480 | } |
486 | 481 | ||
487 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) | 482 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) |
488 | { | 483 | { |
489 | unsigned int i; | 484 | unsigned int i; |
490 | 485 | ||
491 | for (i = 0; i < FORMATS; i++) | 486 | for (i = 0; i < FORMATS; i++) |
492 | if (formats[i].fourcc == fourcc) | 487 | if (formats[i].fourcc == fourcc) |
493 | return formats+i; | 488 | return formats+i; |
494 | return NULL; | 489 | return NULL; |
495 | } | 490 | } |
496 | 491 | ||
497 | /* ----------------------------------------------------------------------- */ | 492 | /* ----------------------------------------------------------------------- */ |
498 | /* resource management */ | 493 | /* resource management */ |
499 | 494 | ||
500 | static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit) | 495 | static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit) |
501 | { | 496 | { |
502 | if (fh->resources & bit) | 497 | if (fh->resources & bit) |
503 | /* have it already allocated */ | 498 | /* have it already allocated */ |
504 | return 1; | 499 | return 1; |
505 | 500 | ||
506 | /* is it free? */ | 501 | /* is it free? */ |
507 | mutex_lock(&dev->lock); | 502 | mutex_lock(&dev->lock); |
508 | if (dev->resources & bit) { | 503 | if (dev->resources & bit) { |
509 | /* no, someone else uses it */ | 504 | /* no, someone else uses it */ |
510 | mutex_unlock(&dev->lock); | 505 | mutex_unlock(&dev->lock); |
511 | return 0; | 506 | return 0; |
512 | } | 507 | } |
513 | /* it's free, grab it */ | 508 | /* it's free, grab it */ |
514 | fh->resources |= bit; | 509 | fh->resources |= bit; |
515 | dev->resources |= bit; | 510 | dev->resources |= bit; |
516 | dprintk("res: get %d\n",bit); | 511 | dprintk("res: get %d\n",bit); |
517 | mutex_unlock(&dev->lock); | 512 | mutex_unlock(&dev->lock); |
518 | return 1; | 513 | return 1; |
519 | } | 514 | } |
520 | 515 | ||
521 | static int res_check(struct saa7134_fh *fh, unsigned int bit) | 516 | static int res_check(struct saa7134_fh *fh, unsigned int bit) |
522 | { | 517 | { |
523 | return (fh->resources & bit); | 518 | return (fh->resources & bit); |
524 | } | 519 | } |
525 | 520 | ||
526 | static int res_locked(struct saa7134_dev *dev, unsigned int bit) | 521 | static int res_locked(struct saa7134_dev *dev, unsigned int bit) |
527 | { | 522 | { |
528 | return (dev->resources & bit); | 523 | return (dev->resources & bit); |
529 | } | 524 | } |
530 | 525 | ||
531 | static | 526 | static |
532 | void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) | 527 | void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) |
533 | { | 528 | { |
534 | BUG_ON((fh->resources & bits) != bits); | 529 | BUG_ON((fh->resources & bits) != bits); |
535 | 530 | ||
536 | mutex_lock(&dev->lock); | 531 | mutex_lock(&dev->lock); |
537 | fh->resources &= ~bits; | 532 | fh->resources &= ~bits; |
538 | dev->resources &= ~bits; | 533 | dev->resources &= ~bits; |
539 | dprintk("res: put %d\n",bits); | 534 | dprintk("res: put %d\n",bits); |
540 | mutex_unlock(&dev->lock); | 535 | mutex_unlock(&dev->lock); |
541 | } | 536 | } |
542 | 537 | ||
543 | /* ------------------------------------------------------------------ */ | 538 | /* ------------------------------------------------------------------ */ |
544 | 539 | ||
545 | static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) | 540 | static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) |
546 | { | 541 | { |
547 | dprintk("set tv norm = %s\n",norm->name); | 542 | dprintk("set tv norm = %s\n",norm->name); |
548 | dev->tvnorm = norm; | 543 | dev->tvnorm = norm; |
549 | 544 | ||
550 | /* setup cropping */ | 545 | /* setup cropping */ |
551 | dev->crop_bounds.left = norm->h_start; | 546 | dev->crop_bounds.left = norm->h_start; |
552 | dev->crop_defrect.left = norm->h_start; | 547 | dev->crop_defrect.left = norm->h_start; |
553 | dev->crop_bounds.width = norm->h_stop - norm->h_start +1; | 548 | dev->crop_bounds.width = norm->h_stop - norm->h_start +1; |
554 | dev->crop_defrect.width = norm->h_stop - norm->h_start +1; | 549 | dev->crop_defrect.width = norm->h_stop - norm->h_start +1; |
555 | 550 | ||
556 | dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; | 551 | dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; |
557 | dev->crop_defrect.top = norm->video_v_start*2; | 552 | dev->crop_defrect.top = norm->video_v_start*2; |
558 | dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) | 553 | dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) |
559 | - dev->crop_bounds.top; | 554 | - dev->crop_bounds.top; |
560 | dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; | 555 | dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; |
561 | 556 | ||
562 | dev->crop_current = dev->crop_defrect; | 557 | dev->crop_current = dev->crop_defrect; |
563 | 558 | ||
564 | saa7134_set_tvnorm_hw(dev); | 559 | saa7134_set_tvnorm_hw(dev); |
565 | } | 560 | } |
566 | 561 | ||
567 | static void video_mux(struct saa7134_dev *dev, int input) | 562 | static void video_mux(struct saa7134_dev *dev, int input) |
568 | { | 563 | { |
569 | dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); | 564 | dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); |
570 | dev->ctl_input = input; | 565 | dev->ctl_input = input; |
571 | set_tvnorm(dev, dev->tvnorm); | 566 | set_tvnorm(dev, dev->tvnorm); |
572 | saa7134_tvaudio_setinput(dev, &card_in(dev, input)); | 567 | saa7134_tvaudio_setinput(dev, &card_in(dev, input)); |
573 | } | 568 | } |
574 | 569 | ||
575 | 570 | ||
576 | static void saa7134_set_decoder(struct saa7134_dev *dev) | 571 | static void saa7134_set_decoder(struct saa7134_dev *dev) |
577 | { | 572 | { |
578 | int luma_control, sync_control, mux; | 573 | int luma_control, sync_control, mux; |
579 | 574 | ||
580 | struct saa7134_tvnorm *norm = dev->tvnorm; | 575 | struct saa7134_tvnorm *norm = dev->tvnorm; |
581 | mux = card_in(dev, dev->ctl_input).vmux; | 576 | mux = card_in(dev, dev->ctl_input).vmux; |
582 | 577 | ||
583 | luma_control = norm->luma_control; | 578 | luma_control = norm->luma_control; |
584 | sync_control = norm->sync_control; | 579 | sync_control = norm->sync_control; |
585 | 580 | ||
586 | if (mux > 5) | 581 | if (mux > 5) |
587 | luma_control |= 0x80; /* svideo */ | 582 | luma_control |= 0x80; /* svideo */ |
588 | if (noninterlaced || dev->nosignal) | 583 | if (noninterlaced || dev->nosignal) |
589 | sync_control |= 0x20; | 584 | sync_control |= 0x20; |
590 | 585 | ||
591 | /* setup video decoder */ | 586 | /* setup video decoder */ |
592 | saa_writeb(SAA7134_INCR_DELAY, 0x08); | 587 | saa_writeb(SAA7134_INCR_DELAY, 0x08); |
593 | saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); | 588 | saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); |
594 | saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); | 589 | saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); |
595 | 590 | ||
596 | saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); | 591 | saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); |
597 | saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); | 592 | saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); |
598 | saa_writeb(SAA7134_HSYNC_START, 0xeb); | 593 | saa_writeb(SAA7134_HSYNC_START, 0xeb); |
599 | saa_writeb(SAA7134_HSYNC_STOP, 0xe0); | 594 | saa_writeb(SAA7134_HSYNC_STOP, 0xe0); |
600 | saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); | 595 | saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); |
601 | 596 | ||
602 | saa_writeb(SAA7134_SYNC_CTRL, sync_control); | 597 | saa_writeb(SAA7134_SYNC_CTRL, sync_control); |
603 | saa_writeb(SAA7134_LUMA_CTRL, luma_control); | 598 | saa_writeb(SAA7134_LUMA_CTRL, luma_control); |
604 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); | 599 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); |
605 | 600 | ||
606 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | 601 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
607 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | 602 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
608 | 603 | ||
609 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | 604 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
610 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | 605 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
611 | 606 | ||
612 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); | 607 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); |
613 | saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); | 608 | saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); |
614 | saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); | 609 | saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); |
615 | 610 | ||
616 | saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); | 611 | saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); |
617 | saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); | 612 | saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); |
618 | 613 | ||
619 | saa_writeb(SAA7134_ANALOG_ADC, 0x01); | 614 | saa_writeb(SAA7134_ANALOG_ADC, 0x01); |
620 | saa_writeb(SAA7134_VGATE_START, 0x11); | 615 | saa_writeb(SAA7134_VGATE_START, 0x11); |
621 | saa_writeb(SAA7134_VGATE_STOP, 0xfe); | 616 | saa_writeb(SAA7134_VGATE_STOP, 0xfe); |
622 | saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); | 617 | saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); |
623 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); | 618 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); |
624 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); | 619 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); |
625 | } | 620 | } |
626 | 621 | ||
627 | void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) | 622 | void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) |
628 | { | 623 | { |
629 | saa7134_set_decoder(dev); | 624 | saa7134_set_decoder(dev); |
630 | 625 | ||
631 | if (card_in(dev, dev->ctl_input).tv) | 626 | if (card_in(dev, dev->ctl_input).tv) |
632 | saa_call_all(dev, tuner, s_std, dev->tvnorm->id); | 627 | saa_call_all(dev, tuner, s_std, dev->tvnorm->id); |
633 | /* Set the correct norm for the saa6752hs. This function | 628 | /* Set the correct norm for the saa6752hs. This function |
634 | does nothing if there is no saa6752hs. */ | 629 | does nothing if there is no saa6752hs. */ |
635 | saa_call_empress(dev, tuner, s_std, dev->tvnorm->id); | 630 | saa_call_empress(dev, tuner, s_std, dev->tvnorm->id); |
636 | } | 631 | } |
637 | 632 | ||
638 | static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) | 633 | static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) |
639 | { | 634 | { |
640 | static const struct { | 635 | static const struct { |
641 | int xpsc; | 636 | int xpsc; |
642 | int xacl; | 637 | int xacl; |
643 | int xc2_1; | 638 | int xc2_1; |
644 | int xdcg; | 639 | int xdcg; |
645 | int vpfy; | 640 | int vpfy; |
646 | } vals[] = { | 641 | } vals[] = { |
647 | /* XPSC XACL XC2_1 XDCG VPFY */ | 642 | /* XPSC XACL XC2_1 XDCG VPFY */ |
648 | { 1, 0, 0, 0, 0 }, | 643 | { 1, 0, 0, 0, 0 }, |
649 | { 2, 2, 1, 2, 2 }, | 644 | { 2, 2, 1, 2, 2 }, |
650 | { 3, 4, 1, 3, 2 }, | 645 | { 3, 4, 1, 3, 2 }, |
651 | { 4, 8, 1, 4, 2 }, | 646 | { 4, 8, 1, 4, 2 }, |
652 | { 5, 8, 1, 4, 2 }, | 647 | { 5, 8, 1, 4, 2 }, |
653 | { 6, 8, 1, 4, 3 }, | 648 | { 6, 8, 1, 4, 3 }, |
654 | { 7, 8, 1, 4, 3 }, | 649 | { 7, 8, 1, 4, 3 }, |
655 | { 8, 15, 0, 4, 3 }, | 650 | { 8, 15, 0, 4, 3 }, |
656 | { 9, 15, 0, 4, 3 }, | 651 | { 9, 15, 0, 4, 3 }, |
657 | { 10, 16, 1, 5, 3 }, | 652 | { 10, 16, 1, 5, 3 }, |
658 | }; | 653 | }; |
659 | static const int count = ARRAY_SIZE(vals); | 654 | static const int count = ARRAY_SIZE(vals); |
660 | int i; | 655 | int i; |
661 | 656 | ||
662 | for (i = 0; i < count; i++) | 657 | for (i = 0; i < count; i++) |
663 | if (vals[i].xpsc == prescale) | 658 | if (vals[i].xpsc == prescale) |
664 | break; | 659 | break; |
665 | if (i == count) | 660 | if (i == count) |
666 | return; | 661 | return; |
667 | 662 | ||
668 | saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); | 663 | saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); |
669 | saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); | 664 | saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); |
670 | saa_writeb(SAA7134_LEVEL_CTRL(task), | 665 | saa_writeb(SAA7134_LEVEL_CTRL(task), |
671 | (vals[i].xc2_1 << 3) | (vals[i].xdcg)); | 666 | (vals[i].xc2_1 << 3) | (vals[i].xdcg)); |
672 | saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, | 667 | saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, |
673 | (vals[i].vpfy << 2) | vals[i].vpfy); | 668 | (vals[i].vpfy << 2) | vals[i].vpfy); |
674 | } | 669 | } |
675 | 670 | ||
676 | static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) | 671 | static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) |
677 | { | 672 | { |
678 | int val,mirror; | 673 | int val,mirror; |
679 | 674 | ||
680 | saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); | 675 | saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); |
681 | saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); | 676 | saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); |
682 | 677 | ||
683 | mirror = (dev->ctl_mirror) ? 0x02 : 0x00; | 678 | mirror = (dev->ctl_mirror) ? 0x02 : 0x00; |
684 | if (yscale < 2048) { | 679 | if (yscale < 2048) { |
685 | /* LPI */ | 680 | /* LPI */ |
686 | dprintk("yscale LPI yscale=%d\n",yscale); | 681 | dprintk("yscale LPI yscale=%d\n",yscale); |
687 | saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); | 682 | saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); |
688 | saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); | 683 | saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); |
689 | saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); | 684 | saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); |
690 | } else { | 685 | } else { |
691 | /* ACM */ | 686 | /* ACM */ |
692 | val = 0x40 * 1024 / yscale; | 687 | val = 0x40 * 1024 / yscale; |
693 | dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); | 688 | dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); |
694 | saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); | 689 | saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); |
695 | saa_writeb(SAA7134_LUMA_CONTRAST(task), val); | 690 | saa_writeb(SAA7134_LUMA_CONTRAST(task), val); |
696 | saa_writeb(SAA7134_CHROMA_SATURATION(task), val); | 691 | saa_writeb(SAA7134_CHROMA_SATURATION(task), val); |
697 | } | 692 | } |
698 | saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); | 693 | saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); |
699 | } | 694 | } |
700 | 695 | ||
701 | static void set_size(struct saa7134_dev *dev, int task, | 696 | static void set_size(struct saa7134_dev *dev, int task, |
702 | int width, int height, int interlace) | 697 | int width, int height, int interlace) |
703 | { | 698 | { |
704 | int prescale,xscale,yscale,y_even,y_odd; | 699 | int prescale,xscale,yscale,y_even,y_odd; |
705 | int h_start, h_stop, v_start, v_stop; | 700 | int h_start, h_stop, v_start, v_stop; |
706 | int div = interlace ? 2 : 1; | 701 | int div = interlace ? 2 : 1; |
707 | 702 | ||
708 | /* setup video scaler */ | 703 | /* setup video scaler */ |
709 | h_start = dev->crop_current.left; | 704 | h_start = dev->crop_current.left; |
710 | v_start = dev->crop_current.top/2; | 705 | v_start = dev->crop_current.top/2; |
711 | h_stop = (dev->crop_current.left + dev->crop_current.width -1); | 706 | h_stop = (dev->crop_current.left + dev->crop_current.width -1); |
712 | v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; | 707 | v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; |
713 | 708 | ||
714 | saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); | 709 | saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); |
715 | saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); | 710 | saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); |
716 | saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); | 711 | saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); |
717 | saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); | 712 | saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); |
718 | saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); | 713 | saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); |
719 | saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); | 714 | saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); |
720 | saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); | 715 | saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); |
721 | saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); | 716 | saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); |
722 | 717 | ||
723 | prescale = dev->crop_current.width / width; | 718 | prescale = dev->crop_current.width / width; |
724 | if (0 == prescale) | 719 | if (0 == prescale) |
725 | prescale = 1; | 720 | prescale = 1; |
726 | xscale = 1024 * dev->crop_current.width / prescale / width; | 721 | xscale = 1024 * dev->crop_current.width / prescale / width; |
727 | yscale = 512 * div * dev->crop_current.height / height; | 722 | yscale = 512 * div * dev->crop_current.height / height; |
728 | dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); | 723 | dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); |
729 | set_h_prescale(dev,task,prescale); | 724 | set_h_prescale(dev,task,prescale); |
730 | saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); | 725 | saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); |
731 | saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); | 726 | saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); |
732 | set_v_scale(dev,task,yscale); | 727 | set_v_scale(dev,task,yscale); |
733 | 728 | ||
734 | saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); | 729 | saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); |
735 | saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); | 730 | saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); |
736 | saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); | 731 | saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); |
737 | saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); | 732 | saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); |
738 | 733 | ||
739 | /* deinterlace y offsets */ | 734 | /* deinterlace y offsets */ |
740 | y_odd = dev->ctl_y_odd; | 735 | y_odd = dev->ctl_y_odd; |
741 | y_even = dev->ctl_y_even; | 736 | y_even = dev->ctl_y_even; |
742 | saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); | 737 | saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); |
743 | saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); | 738 | saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); |
744 | saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); | 739 | saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); |
745 | saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); | 740 | saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); |
746 | } | 741 | } |
747 | 742 | ||
748 | /* ------------------------------------------------------------------ */ | 743 | /* ------------------------------------------------------------------ */ |
749 | 744 | ||
750 | struct cliplist { | 745 | struct cliplist { |
751 | __u16 position; | 746 | __u16 position; |
752 | __u8 enable; | 747 | __u8 enable; |
753 | __u8 disable; | 748 | __u8 disable; |
754 | }; | 749 | }; |
755 | 750 | ||
756 | static void set_cliplist(struct saa7134_dev *dev, int reg, | 751 | static void set_cliplist(struct saa7134_dev *dev, int reg, |
757 | struct cliplist *cl, int entries, char *name) | 752 | struct cliplist *cl, int entries, char *name) |
758 | { | 753 | { |
759 | __u8 winbits = 0; | 754 | __u8 winbits = 0; |
760 | int i; | 755 | int i; |
761 | 756 | ||
762 | for (i = 0; i < entries; i++) { | 757 | for (i = 0; i < entries; i++) { |
763 | winbits |= cl[i].enable; | 758 | winbits |= cl[i].enable; |
764 | winbits &= ~cl[i].disable; | 759 | winbits &= ~cl[i].disable; |
765 | if (i < 15 && cl[i].position == cl[i+1].position) | 760 | if (i < 15 && cl[i].position == cl[i+1].position) |
766 | continue; | 761 | continue; |
767 | saa_writeb(reg + 0, winbits); | 762 | saa_writeb(reg + 0, winbits); |
768 | saa_writeb(reg + 2, cl[i].position & 0xff); | 763 | saa_writeb(reg + 2, cl[i].position & 0xff); |
769 | saa_writeb(reg + 3, cl[i].position >> 8); | 764 | saa_writeb(reg + 3, cl[i].position >> 8); |
770 | dprintk("clip: %s winbits=%02x pos=%d\n", | 765 | dprintk("clip: %s winbits=%02x pos=%d\n", |
771 | name,winbits,cl[i].position); | 766 | name,winbits,cl[i].position); |
772 | reg += 8; | 767 | reg += 8; |
773 | } | 768 | } |
774 | for (; reg < 0x400; reg += 8) { | 769 | for (; reg < 0x400; reg += 8) { |
775 | saa_writeb(reg+ 0, 0); | 770 | saa_writeb(reg+ 0, 0); |
776 | saa_writeb(reg + 1, 0); | 771 | saa_writeb(reg + 1, 0); |
777 | saa_writeb(reg + 2, 0); | 772 | saa_writeb(reg + 2, 0); |
778 | saa_writeb(reg + 3, 0); | 773 | saa_writeb(reg + 3, 0); |
779 | } | 774 | } |
780 | } | 775 | } |
781 | 776 | ||
782 | static int clip_range(int val) | 777 | static int clip_range(int val) |
783 | { | 778 | { |
784 | if (val < 0) | 779 | if (val < 0) |
785 | val = 0; | 780 | val = 0; |
786 | return val; | 781 | return val; |
787 | } | 782 | } |
788 | 783 | ||
789 | /* Sort into smallest position first order */ | 784 | /* Sort into smallest position first order */ |
790 | static int cliplist_cmp(const void *a, const void *b) | 785 | static int cliplist_cmp(const void *a, const void *b) |
791 | { | 786 | { |
792 | const struct cliplist *cla = a; | 787 | const struct cliplist *cla = a; |
793 | const struct cliplist *clb = b; | 788 | const struct cliplist *clb = b; |
794 | if (cla->position < clb->position) | 789 | if (cla->position < clb->position) |
795 | return -1; | 790 | return -1; |
796 | if (cla->position > clb->position) | 791 | if (cla->position > clb->position) |
797 | return 1; | 792 | return 1; |
798 | return 0; | 793 | return 0; |
799 | } | 794 | } |
800 | 795 | ||
801 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | 796 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, |
802 | int nclips, int interlace) | 797 | int nclips, int interlace) |
803 | { | 798 | { |
804 | struct cliplist col[16], row[16]; | 799 | struct cliplist col[16], row[16]; |
805 | int cols = 0, rows = 0, i; | 800 | int cols = 0, rows = 0, i; |
806 | int div = interlace ? 2 : 1; | 801 | int div = interlace ? 2 : 1; |
807 | 802 | ||
808 | memset(col, 0, sizeof(col)); | 803 | memset(col, 0, sizeof(col)); |
809 | memset(row, 0, sizeof(row)); | 804 | memset(row, 0, sizeof(row)); |
810 | for (i = 0; i < nclips && i < 8; i++) { | 805 | for (i = 0; i < nclips && i < 8; i++) { |
811 | col[cols].position = clip_range(clips[i].c.left); | 806 | col[cols].position = clip_range(clips[i].c.left); |
812 | col[cols].enable = (1 << i); | 807 | col[cols].enable = (1 << i); |
813 | cols++; | 808 | cols++; |
814 | col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); | 809 | col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); |
815 | col[cols].disable = (1 << i); | 810 | col[cols].disable = (1 << i); |
816 | cols++; | 811 | cols++; |
817 | row[rows].position = clip_range(clips[i].c.top / div); | 812 | row[rows].position = clip_range(clips[i].c.top / div); |
818 | row[rows].enable = (1 << i); | 813 | row[rows].enable = (1 << i); |
819 | rows++; | 814 | rows++; |
820 | row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) | 815 | row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) |
821 | / div); | 816 | / div); |
822 | row[rows].disable = (1 << i); | 817 | row[rows].disable = (1 << i); |
823 | rows++; | 818 | rows++; |
824 | } | 819 | } |
825 | sort(col, cols, sizeof col[0], cliplist_cmp, NULL); | 820 | sort(col, cols, sizeof col[0], cliplist_cmp, NULL); |
826 | sort(row, rows, sizeof row[0], cliplist_cmp, NULL); | 821 | sort(row, rows, sizeof row[0], cliplist_cmp, NULL); |
827 | set_cliplist(dev,0x380,col,cols,"cols"); | 822 | set_cliplist(dev,0x380,col,cols,"cols"); |
828 | set_cliplist(dev,0x384,row,rows,"rows"); | 823 | set_cliplist(dev,0x384,row,rows,"rows"); |
829 | return 0; | 824 | return 0; |
830 | } | 825 | } |
831 | 826 | ||
832 | static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) | 827 | static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) |
833 | { | 828 | { |
834 | enum v4l2_field field; | 829 | enum v4l2_field field; |
835 | int maxw, maxh; | 830 | int maxw, maxh; |
836 | 831 | ||
837 | if (NULL == dev->ovbuf.base) | 832 | if (NULL == dev->ovbuf.base) |
838 | return -EINVAL; | 833 | return -EINVAL; |
839 | if (NULL == dev->ovfmt) | 834 | if (NULL == dev->ovfmt) |
840 | return -EINVAL; | 835 | return -EINVAL; |
841 | if (win->w.width < 48 || win->w.height < 32) | 836 | if (win->w.width < 48 || win->w.height < 32) |
842 | return -EINVAL; | 837 | return -EINVAL; |
843 | if (win->clipcount > 2048) | 838 | if (win->clipcount > 2048) |
844 | return -EINVAL; | 839 | return -EINVAL; |
845 | 840 | ||
846 | field = win->field; | 841 | field = win->field; |
847 | maxw = dev->crop_current.width; | 842 | maxw = dev->crop_current.width; |
848 | maxh = dev->crop_current.height; | 843 | maxh = dev->crop_current.height; |
849 | 844 | ||
850 | if (V4L2_FIELD_ANY == field) { | 845 | if (V4L2_FIELD_ANY == field) { |
851 | field = (win->w.height > maxh/2) | 846 | field = (win->w.height > maxh/2) |
852 | ? V4L2_FIELD_INTERLACED | 847 | ? V4L2_FIELD_INTERLACED |
853 | : V4L2_FIELD_TOP; | 848 | : V4L2_FIELD_TOP; |
854 | } | 849 | } |
855 | switch (field) { | 850 | switch (field) { |
856 | case V4L2_FIELD_TOP: | 851 | case V4L2_FIELD_TOP: |
857 | case V4L2_FIELD_BOTTOM: | 852 | case V4L2_FIELD_BOTTOM: |
858 | maxh = maxh / 2; | 853 | maxh = maxh / 2; |
859 | break; | 854 | break; |
860 | case V4L2_FIELD_INTERLACED: | 855 | case V4L2_FIELD_INTERLACED: |
861 | break; | 856 | break; |
862 | default: | 857 | default: |
863 | return -EINVAL; | 858 | return -EINVAL; |
864 | } | 859 | } |
865 | 860 | ||
866 | win->field = field; | 861 | win->field = field; |
867 | if (win->w.width > maxw) | 862 | if (win->w.width > maxw) |
868 | win->w.width = maxw; | 863 | win->w.width = maxw; |
869 | if (win->w.height > maxh) | 864 | if (win->w.height > maxh) |
870 | win->w.height = maxh; | 865 | win->w.height = maxh; |
871 | return 0; | 866 | return 0; |
872 | } | 867 | } |
873 | 868 | ||
874 | static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | 869 | static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) |
875 | { | 870 | { |
876 | unsigned long base,control,bpl; | 871 | unsigned long base,control,bpl; |
877 | int err; | 872 | int err; |
878 | 873 | ||
879 | err = verify_preview(dev,&fh->win); | 874 | err = verify_preview(dev,&fh->win); |
880 | if (0 != err) | 875 | if (0 != err) |
881 | return err; | 876 | return err; |
882 | 877 | ||
883 | dev->ovfield = fh->win.field; | 878 | dev->ovfield = fh->win.field; |
884 | dprintk("start_preview %dx%d+%d+%d %s field=%s\n", | 879 | dprintk("start_preview %dx%d+%d+%d %s field=%s\n", |
885 | fh->win.w.width,fh->win.w.height, | 880 | fh->win.w.width,fh->win.w.height, |
886 | fh->win.w.left,fh->win.w.top, | 881 | fh->win.w.left,fh->win.w.top, |
887 | dev->ovfmt->name,v4l2_field_names[dev->ovfield]); | 882 | dev->ovfmt->name,v4l2_field_names[dev->ovfield]); |
888 | 883 | ||
889 | /* setup window + clipping */ | 884 | /* setup window + clipping */ |
890 | set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, | 885 | set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, |
891 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); | 886 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); |
892 | setup_clipping(dev,fh->clips,fh->nclips, | 887 | setup_clipping(dev,fh->clips,fh->nclips, |
893 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); | 888 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); |
894 | if (dev->ovfmt->yuv) | 889 | if (dev->ovfmt->yuv) |
895 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); | 890 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); |
896 | else | 891 | else |
897 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); | 892 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); |
898 | saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); | 893 | saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); |
899 | 894 | ||
900 | /* dma: setup channel 1 (= Video Task B) */ | 895 | /* dma: setup channel 1 (= Video Task B) */ |
901 | base = (unsigned long)dev->ovbuf.base; | 896 | base = (unsigned long)dev->ovbuf.base; |
902 | base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; | 897 | base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; |
903 | base += dev->ovfmt->depth/8 * fh->win.w.left; | 898 | base += dev->ovfmt->depth/8 * fh->win.w.left; |
904 | bpl = dev->ovbuf.fmt.bytesperline; | 899 | bpl = dev->ovbuf.fmt.bytesperline; |
905 | control = SAA7134_RS_CONTROL_BURST_16; | 900 | control = SAA7134_RS_CONTROL_BURST_16; |
906 | if (dev->ovfmt->bswap) | 901 | if (dev->ovfmt->bswap) |
907 | control |= SAA7134_RS_CONTROL_BSWAP; | 902 | control |= SAA7134_RS_CONTROL_BSWAP; |
908 | if (dev->ovfmt->wswap) | 903 | if (dev->ovfmt->wswap) |
909 | control |= SAA7134_RS_CONTROL_WSWAP; | 904 | control |= SAA7134_RS_CONTROL_WSWAP; |
910 | if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { | 905 | if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { |
911 | saa_writel(SAA7134_RS_BA1(1),base); | 906 | saa_writel(SAA7134_RS_BA1(1),base); |
912 | saa_writel(SAA7134_RS_BA2(1),base+bpl); | 907 | saa_writel(SAA7134_RS_BA2(1),base+bpl); |
913 | saa_writel(SAA7134_RS_PITCH(1),bpl*2); | 908 | saa_writel(SAA7134_RS_PITCH(1),bpl*2); |
914 | saa_writel(SAA7134_RS_CONTROL(1),control); | 909 | saa_writel(SAA7134_RS_CONTROL(1),control); |
915 | } else { | 910 | } else { |
916 | saa_writel(SAA7134_RS_BA1(1),base); | 911 | saa_writel(SAA7134_RS_BA1(1),base); |
917 | saa_writel(SAA7134_RS_BA2(1),base); | 912 | saa_writel(SAA7134_RS_BA2(1),base); |
918 | saa_writel(SAA7134_RS_PITCH(1),bpl); | 913 | saa_writel(SAA7134_RS_PITCH(1),bpl); |
919 | saa_writel(SAA7134_RS_CONTROL(1),control); | 914 | saa_writel(SAA7134_RS_CONTROL(1),control); |
920 | } | 915 | } |
921 | 916 | ||
922 | /* start dma */ | 917 | /* start dma */ |
923 | dev->ovenable = 1; | 918 | dev->ovenable = 1; |
924 | saa7134_set_dmabits(dev); | 919 | saa7134_set_dmabits(dev); |
925 | 920 | ||
926 | return 0; | 921 | return 0; |
927 | } | 922 | } |
928 | 923 | ||
929 | static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | 924 | static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) |
930 | { | 925 | { |
931 | dev->ovenable = 0; | 926 | dev->ovenable = 0; |
932 | saa7134_set_dmabits(dev); | 927 | saa7134_set_dmabits(dev); |
933 | return 0; | 928 | return 0; |
934 | } | 929 | } |
935 | 930 | ||
936 | /* ------------------------------------------------------------------ */ | 931 | /* ------------------------------------------------------------------ */ |
937 | 932 | ||
938 | static int buffer_activate(struct saa7134_dev *dev, | 933 | static int buffer_activate(struct saa7134_dev *dev, |
939 | struct saa7134_buf *buf, | 934 | struct saa7134_buf *buf, |
940 | struct saa7134_buf *next) | 935 | struct saa7134_buf *next) |
941 | { | 936 | { |
942 | unsigned long base,control,bpl; | 937 | unsigned long base,control,bpl; |
943 | unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ | 938 | unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ |
944 | 939 | ||
945 | dprintk("buffer_activate buf=%p\n",buf); | 940 | dprintk("buffer_activate buf=%p\n",buf); |
946 | buf->vb.state = VIDEOBUF_ACTIVE; | 941 | buf->vb.state = VIDEOBUF_ACTIVE; |
947 | buf->top_seen = 0; | 942 | buf->top_seen = 0; |
948 | 943 | ||
949 | set_size(dev,TASK_A,buf->vb.width,buf->vb.height, | 944 | set_size(dev,TASK_A,buf->vb.width,buf->vb.height, |
950 | V4L2_FIELD_HAS_BOTH(buf->vb.field)); | 945 | V4L2_FIELD_HAS_BOTH(buf->vb.field)); |
951 | if (buf->fmt->yuv) | 946 | if (buf->fmt->yuv) |
952 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); | 947 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); |
953 | else | 948 | else |
954 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); | 949 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); |
955 | saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); | 950 | saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); |
956 | 951 | ||
957 | /* DMA: setup channel 0 (= Video Task A0) */ | 952 | /* DMA: setup channel 0 (= Video Task A0) */ |
958 | base = saa7134_buffer_base(buf); | 953 | base = saa7134_buffer_base(buf); |
959 | if (buf->fmt->planar) | 954 | if (buf->fmt->planar) |
960 | bpl = buf->vb.width; | 955 | bpl = buf->vb.width; |
961 | else | 956 | else |
962 | bpl = (buf->vb.width * buf->fmt->depth) / 8; | 957 | bpl = (buf->vb.width * buf->fmt->depth) / 8; |
963 | control = SAA7134_RS_CONTROL_BURST_16 | | 958 | control = SAA7134_RS_CONTROL_BURST_16 | |
964 | SAA7134_RS_CONTROL_ME | | 959 | SAA7134_RS_CONTROL_ME | |
965 | (buf->pt->dma >> 12); | 960 | (buf->pt->dma >> 12); |
966 | if (buf->fmt->bswap) | 961 | if (buf->fmt->bswap) |
967 | control |= SAA7134_RS_CONTROL_BSWAP; | 962 | control |= SAA7134_RS_CONTROL_BSWAP; |
968 | if (buf->fmt->wswap) | 963 | if (buf->fmt->wswap) |
969 | control |= SAA7134_RS_CONTROL_WSWAP; | 964 | control |= SAA7134_RS_CONTROL_WSWAP; |
970 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { | 965 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { |
971 | /* interlaced */ | 966 | /* interlaced */ |
972 | saa_writel(SAA7134_RS_BA1(0),base); | 967 | saa_writel(SAA7134_RS_BA1(0),base); |
973 | saa_writel(SAA7134_RS_BA2(0),base+bpl); | 968 | saa_writel(SAA7134_RS_BA2(0),base+bpl); |
974 | saa_writel(SAA7134_RS_PITCH(0),bpl*2); | 969 | saa_writel(SAA7134_RS_PITCH(0),bpl*2); |
975 | } else { | 970 | } else { |
976 | /* non-interlaced */ | 971 | /* non-interlaced */ |
977 | saa_writel(SAA7134_RS_BA1(0),base); | 972 | saa_writel(SAA7134_RS_BA1(0),base); |
978 | saa_writel(SAA7134_RS_BA2(0),base); | 973 | saa_writel(SAA7134_RS_BA2(0),base); |
979 | saa_writel(SAA7134_RS_PITCH(0),bpl); | 974 | saa_writel(SAA7134_RS_PITCH(0),bpl); |
980 | } | 975 | } |
981 | saa_writel(SAA7134_RS_CONTROL(0),control); | 976 | saa_writel(SAA7134_RS_CONTROL(0),control); |
982 | 977 | ||
983 | if (buf->fmt->planar) { | 978 | if (buf->fmt->planar) { |
984 | /* DMA: setup channel 4+5 (= planar task A) */ | 979 | /* DMA: setup channel 4+5 (= planar task A) */ |
985 | bpl_uv = bpl >> buf->fmt->hshift; | 980 | bpl_uv = bpl >> buf->fmt->hshift; |
986 | lines_uv = buf->vb.height >> buf->fmt->vshift; | 981 | lines_uv = buf->vb.height >> buf->fmt->vshift; |
987 | base2 = base + bpl * buf->vb.height; | 982 | base2 = base + bpl * buf->vb.height; |
988 | base3 = base2 + bpl_uv * lines_uv; | 983 | base3 = base2 + bpl_uv * lines_uv; |
989 | if (buf->fmt->uvswap) | 984 | if (buf->fmt->uvswap) |
990 | tmp = base2, base2 = base3, base3 = tmp; | 985 | tmp = base2, base2 = base3, base3 = tmp; |
991 | dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", | 986 | dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", |
992 | bpl_uv,lines_uv,base2,base3); | 987 | bpl_uv,lines_uv,base2,base3); |
993 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { | 988 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { |
994 | /* interlaced */ | 989 | /* interlaced */ |
995 | saa_writel(SAA7134_RS_BA1(4),base2); | 990 | saa_writel(SAA7134_RS_BA1(4),base2); |
996 | saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); | 991 | saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); |
997 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); | 992 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); |
998 | saa_writel(SAA7134_RS_BA1(5),base3); | 993 | saa_writel(SAA7134_RS_BA1(5),base3); |
999 | saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); | 994 | saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); |
1000 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); | 995 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); |
1001 | } else { | 996 | } else { |
1002 | /* non-interlaced */ | 997 | /* non-interlaced */ |
1003 | saa_writel(SAA7134_RS_BA1(4),base2); | 998 | saa_writel(SAA7134_RS_BA1(4),base2); |
1004 | saa_writel(SAA7134_RS_BA2(4),base2); | 999 | saa_writel(SAA7134_RS_BA2(4),base2); |
1005 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv); | 1000 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv); |
1006 | saa_writel(SAA7134_RS_BA1(5),base3); | 1001 | saa_writel(SAA7134_RS_BA1(5),base3); |
1007 | saa_writel(SAA7134_RS_BA2(5),base3); | 1002 | saa_writel(SAA7134_RS_BA2(5),base3); |
1008 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv); | 1003 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv); |
1009 | } | 1004 | } |
1010 | saa_writel(SAA7134_RS_CONTROL(4),control); | 1005 | saa_writel(SAA7134_RS_CONTROL(4),control); |
1011 | saa_writel(SAA7134_RS_CONTROL(5),control); | 1006 | saa_writel(SAA7134_RS_CONTROL(5),control); |
1012 | } | 1007 | } |
1013 | 1008 | ||
1014 | /* start DMA */ | 1009 | /* start DMA */ |
1015 | saa7134_set_dmabits(dev); | 1010 | saa7134_set_dmabits(dev); |
1016 | mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); | 1011 | mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); |
1017 | return 0; | 1012 | return 0; |
1018 | } | 1013 | } |
1019 | 1014 | ||
1020 | static int buffer_prepare(struct videobuf_queue *q, | 1015 | static int buffer_prepare(struct videobuf_queue *q, |
1021 | struct videobuf_buffer *vb, | 1016 | struct videobuf_buffer *vb, |
1022 | enum v4l2_field field) | 1017 | enum v4l2_field field) |
1023 | { | 1018 | { |
1024 | struct saa7134_fh *fh = q->priv_data; | 1019 | struct saa7134_fh *fh = q->priv_data; |
1025 | struct saa7134_dev *dev = fh->dev; | 1020 | struct saa7134_dev *dev = fh->dev; |
1026 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 1021 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
1027 | unsigned int size; | 1022 | unsigned int size; |
1028 | int err; | 1023 | int err; |
1029 | 1024 | ||
1030 | /* sanity checks */ | 1025 | /* sanity checks */ |
1031 | if (NULL == fh->fmt) | 1026 | if (NULL == fh->fmt) |
1032 | return -EINVAL; | 1027 | return -EINVAL; |
1033 | if (fh->width < 48 || | 1028 | if (fh->width < 48 || |
1034 | fh->height < 32 || | 1029 | fh->height < 32 || |
1035 | fh->width/4 > dev->crop_current.width || | 1030 | fh->width/4 > dev->crop_current.width || |
1036 | fh->height/4 > dev->crop_current.height || | 1031 | fh->height/4 > dev->crop_current.height || |
1037 | fh->width > dev->crop_bounds.width || | 1032 | fh->width > dev->crop_bounds.width || |
1038 | fh->height > dev->crop_bounds.height) | 1033 | fh->height > dev->crop_bounds.height) |
1039 | return -EINVAL; | 1034 | return -EINVAL; |
1040 | size = (fh->width * fh->height * fh->fmt->depth) >> 3; | 1035 | size = (fh->width * fh->height * fh->fmt->depth) >> 3; |
1041 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | 1036 | if (0 != buf->vb.baddr && buf->vb.bsize < size) |
1042 | return -EINVAL; | 1037 | return -EINVAL; |
1043 | 1038 | ||
1044 | dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", | 1039 | dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", |
1045 | vb->i,fh->width,fh->height,size,v4l2_field_names[field], | 1040 | vb->i,fh->width,fh->height,size,v4l2_field_names[field], |
1046 | fh->fmt->name); | 1041 | fh->fmt->name); |
1047 | if (buf->vb.width != fh->width || | 1042 | if (buf->vb.width != fh->width || |
1048 | buf->vb.height != fh->height || | 1043 | buf->vb.height != fh->height || |
1049 | buf->vb.size != size || | 1044 | buf->vb.size != size || |
1050 | buf->vb.field != field || | 1045 | buf->vb.field != field || |
1051 | buf->fmt != fh->fmt) { | 1046 | buf->fmt != fh->fmt) { |
1052 | saa7134_dma_free(q,buf); | 1047 | saa7134_dma_free(q,buf); |
1053 | } | 1048 | } |
1054 | 1049 | ||
1055 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 1050 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
1056 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | 1051 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); |
1057 | 1052 | ||
1058 | buf->vb.width = fh->width; | 1053 | buf->vb.width = fh->width; |
1059 | buf->vb.height = fh->height; | 1054 | buf->vb.height = fh->height; |
1060 | buf->vb.size = size; | 1055 | buf->vb.size = size; |
1061 | buf->vb.field = field; | 1056 | buf->vb.field = field; |
1062 | buf->fmt = fh->fmt; | 1057 | buf->fmt = fh->fmt; |
1063 | buf->pt = &fh->pt_cap; | 1058 | buf->pt = &fh->pt_cap; |
1064 | 1059 | ||
1065 | err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); | 1060 | err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); |
1066 | if (err) | 1061 | if (err) |
1067 | goto oops; | 1062 | goto oops; |
1068 | err = saa7134_pgtable_build(dev->pci,buf->pt, | 1063 | err = saa7134_pgtable_build(dev->pci,buf->pt, |
1069 | dma->sglist, | 1064 | dma->sglist, |
1070 | dma->sglen, | 1065 | dma->sglen, |
1071 | saa7134_buffer_startpage(buf)); | 1066 | saa7134_buffer_startpage(buf)); |
1072 | if (err) | 1067 | if (err) |
1073 | goto oops; | 1068 | goto oops; |
1074 | } | 1069 | } |
1075 | buf->vb.state = VIDEOBUF_PREPARED; | 1070 | buf->vb.state = VIDEOBUF_PREPARED; |
1076 | buf->activate = buffer_activate; | 1071 | buf->activate = buffer_activate; |
1077 | return 0; | 1072 | return 0; |
1078 | 1073 | ||
1079 | oops: | 1074 | oops: |
1080 | saa7134_dma_free(q,buf); | 1075 | saa7134_dma_free(q,buf); |
1081 | return err; | 1076 | return err; |
1082 | } | 1077 | } |
1083 | 1078 | ||
1084 | static int | 1079 | static int |
1085 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | 1080 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) |
1086 | { | 1081 | { |
1087 | struct saa7134_fh *fh = q->priv_data; | 1082 | struct saa7134_fh *fh = q->priv_data; |
1088 | 1083 | ||
1089 | *size = fh->fmt->depth * fh->width * fh->height >> 3; | 1084 | *size = fh->fmt->depth * fh->width * fh->height >> 3; |
1090 | if (0 == *count) | 1085 | if (0 == *count) |
1091 | *count = gbuffers; | 1086 | *count = gbuffers; |
1092 | *count = saa7134_buffer_count(*size,*count); | 1087 | *count = saa7134_buffer_count(*size,*count); |
1093 | return 0; | 1088 | return 0; |
1094 | } | 1089 | } |
1095 | 1090 | ||
1096 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | 1091 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) |
1097 | { | 1092 | { |
1098 | struct saa7134_fh *fh = q->priv_data; | 1093 | struct saa7134_fh *fh = q->priv_data; |
1099 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 1094 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
1100 | 1095 | ||
1101 | saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); | 1096 | saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); |
1102 | } | 1097 | } |
1103 | 1098 | ||
1104 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | 1099 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) |
1105 | { | 1100 | { |
1106 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | 1101 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); |
1107 | 1102 | ||
1108 | saa7134_dma_free(q,buf); | 1103 | saa7134_dma_free(q,buf); |
1109 | } | 1104 | } |
1110 | 1105 | ||
1111 | static struct videobuf_queue_ops video_qops = { | 1106 | static struct videobuf_queue_ops video_qops = { |
1112 | .buf_setup = buffer_setup, | 1107 | .buf_setup = buffer_setup, |
1113 | .buf_prepare = buffer_prepare, | 1108 | .buf_prepare = buffer_prepare, |
1114 | .buf_queue = buffer_queue, | 1109 | .buf_queue = buffer_queue, |
1115 | .buf_release = buffer_release, | 1110 | .buf_release = buffer_release, |
1116 | }; | 1111 | }; |
1117 | 1112 | ||
1118 | /* ------------------------------------------------------------------ */ | 1113 | /* ------------------------------------------------------------------ */ |
1119 | 1114 | ||
1120 | int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) | 1115 | int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) |
1121 | { | 1116 | { |
1122 | const struct v4l2_queryctrl* ctrl; | 1117 | const struct v4l2_queryctrl* ctrl; |
1123 | 1118 | ||
1124 | ctrl = ctrl_by_id(c->id); | 1119 | ctrl = ctrl_by_id(c->id); |
1125 | if (NULL == ctrl) | 1120 | if (NULL == ctrl) |
1126 | return -EINVAL; | 1121 | return -EINVAL; |
1127 | switch (c->id) { | 1122 | switch (c->id) { |
1128 | case V4L2_CID_BRIGHTNESS: | 1123 | case V4L2_CID_BRIGHTNESS: |
1129 | c->value = dev->ctl_bright; | 1124 | c->value = dev->ctl_bright; |
1130 | break; | 1125 | break; |
1131 | case V4L2_CID_HUE: | 1126 | case V4L2_CID_HUE: |
1132 | c->value = dev->ctl_hue; | 1127 | c->value = dev->ctl_hue; |
1133 | break; | 1128 | break; |
1134 | case V4L2_CID_CONTRAST: | 1129 | case V4L2_CID_CONTRAST: |
1135 | c->value = dev->ctl_contrast; | 1130 | c->value = dev->ctl_contrast; |
1136 | break; | 1131 | break; |
1137 | case V4L2_CID_SATURATION: | 1132 | case V4L2_CID_SATURATION: |
1138 | c->value = dev->ctl_saturation; | 1133 | c->value = dev->ctl_saturation; |
1139 | break; | 1134 | break; |
1140 | case V4L2_CID_AUDIO_MUTE: | 1135 | case V4L2_CID_AUDIO_MUTE: |
1141 | c->value = dev->ctl_mute; | 1136 | c->value = dev->ctl_mute; |
1142 | break; | 1137 | break; |
1143 | case V4L2_CID_AUDIO_VOLUME: | 1138 | case V4L2_CID_AUDIO_VOLUME: |
1144 | c->value = dev->ctl_volume; | 1139 | c->value = dev->ctl_volume; |
1145 | break; | 1140 | break; |
1146 | case V4L2_CID_PRIVATE_INVERT: | 1141 | case V4L2_CID_PRIVATE_INVERT: |
1147 | c->value = dev->ctl_invert; | 1142 | c->value = dev->ctl_invert; |
1148 | break; | 1143 | break; |
1149 | case V4L2_CID_HFLIP: | 1144 | case V4L2_CID_HFLIP: |
1150 | c->value = dev->ctl_mirror; | 1145 | c->value = dev->ctl_mirror; |
1151 | break; | 1146 | break; |
1152 | case V4L2_CID_PRIVATE_Y_EVEN: | 1147 | case V4L2_CID_PRIVATE_Y_EVEN: |
1153 | c->value = dev->ctl_y_even; | 1148 | c->value = dev->ctl_y_even; |
1154 | break; | 1149 | break; |
1155 | case V4L2_CID_PRIVATE_Y_ODD: | 1150 | case V4L2_CID_PRIVATE_Y_ODD: |
1156 | c->value = dev->ctl_y_odd; | 1151 | c->value = dev->ctl_y_odd; |
1157 | break; | 1152 | break; |
1158 | case V4L2_CID_PRIVATE_AUTOMUTE: | 1153 | case V4L2_CID_PRIVATE_AUTOMUTE: |
1159 | c->value = dev->ctl_automute; | 1154 | c->value = dev->ctl_automute; |
1160 | break; | 1155 | break; |
1161 | default: | 1156 | default: |
1162 | return -EINVAL; | 1157 | return -EINVAL; |
1163 | } | 1158 | } |
1164 | return 0; | 1159 | return 0; |
1165 | } | 1160 | } |
1166 | EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); | 1161 | EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); |
1167 | 1162 | ||
1168 | static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) | 1163 | static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) |
1169 | { | 1164 | { |
1170 | struct saa7134_fh *fh = priv; | 1165 | struct saa7134_fh *fh = priv; |
1171 | 1166 | ||
1172 | return saa7134_g_ctrl_internal(fh->dev, fh, c); | 1167 | return saa7134_g_ctrl_internal(fh->dev, fh, c); |
1173 | } | 1168 | } |
1174 | 1169 | ||
1175 | int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) | 1170 | int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) |
1176 | { | 1171 | { |
1177 | const struct v4l2_queryctrl* ctrl; | 1172 | const struct v4l2_queryctrl* ctrl; |
1178 | unsigned long flags; | 1173 | unsigned long flags; |
1179 | int restart_overlay = 0; | 1174 | int restart_overlay = 0; |
1180 | int err; | 1175 | int err; |
1181 | 1176 | ||
1182 | /* When called from the empress code fh == NULL. | 1177 | /* When called from the empress code fh == NULL. |
1183 | That needs to be fixed somehow, but for now this is | 1178 | That needs to be fixed somehow, but for now this is |
1184 | good enough. */ | 1179 | good enough. */ |
1185 | if (fh) { | 1180 | if (fh) { |
1186 | err = v4l2_prio_check(&dev->prio, &fh->prio); | 1181 | err = v4l2_prio_check(&dev->prio, &fh->prio); |
1187 | if (0 != err) | 1182 | if (0 != err) |
1188 | return err; | 1183 | return err; |
1189 | } | 1184 | } |
1190 | err = -EINVAL; | 1185 | err = -EINVAL; |
1191 | 1186 | ||
1192 | mutex_lock(&dev->lock); | 1187 | mutex_lock(&dev->lock); |
1193 | 1188 | ||
1194 | ctrl = ctrl_by_id(c->id); | 1189 | ctrl = ctrl_by_id(c->id); |
1195 | if (NULL == ctrl) | 1190 | if (NULL == ctrl) |
1196 | goto error; | 1191 | goto error; |
1197 | 1192 | ||
1198 | dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); | 1193 | dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); |
1199 | switch (ctrl->type) { | 1194 | switch (ctrl->type) { |
1200 | case V4L2_CTRL_TYPE_BOOLEAN: | 1195 | case V4L2_CTRL_TYPE_BOOLEAN: |
1201 | case V4L2_CTRL_TYPE_MENU: | 1196 | case V4L2_CTRL_TYPE_MENU: |
1202 | case V4L2_CTRL_TYPE_INTEGER: | 1197 | case V4L2_CTRL_TYPE_INTEGER: |
1203 | if (c->value < ctrl->minimum) | 1198 | if (c->value < ctrl->minimum) |
1204 | c->value = ctrl->minimum; | 1199 | c->value = ctrl->minimum; |
1205 | if (c->value > ctrl->maximum) | 1200 | if (c->value > ctrl->maximum) |
1206 | c->value = ctrl->maximum; | 1201 | c->value = ctrl->maximum; |
1207 | break; | 1202 | break; |
1208 | default: | 1203 | default: |
1209 | /* nothing */; | 1204 | /* nothing */; |
1210 | }; | 1205 | }; |
1211 | switch (c->id) { | 1206 | switch (c->id) { |
1212 | case V4L2_CID_BRIGHTNESS: | 1207 | case V4L2_CID_BRIGHTNESS: |
1213 | dev->ctl_bright = c->value; | 1208 | dev->ctl_bright = c->value; |
1214 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); | 1209 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); |
1215 | break; | 1210 | break; |
1216 | case V4L2_CID_HUE: | 1211 | case V4L2_CID_HUE: |
1217 | dev->ctl_hue = c->value; | 1212 | dev->ctl_hue = c->value; |
1218 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); | 1213 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); |
1219 | break; | 1214 | break; |
1220 | case V4L2_CID_CONTRAST: | 1215 | case V4L2_CID_CONTRAST: |
1221 | dev->ctl_contrast = c->value; | 1216 | dev->ctl_contrast = c->value; |
1222 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | 1217 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
1223 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | 1218 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
1224 | break; | 1219 | break; |
1225 | case V4L2_CID_SATURATION: | 1220 | case V4L2_CID_SATURATION: |
1226 | dev->ctl_saturation = c->value; | 1221 | dev->ctl_saturation = c->value; |
1227 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | 1222 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
1228 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | 1223 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
1229 | break; | 1224 | break; |
1230 | case V4L2_CID_AUDIO_MUTE: | 1225 | case V4L2_CID_AUDIO_MUTE: |
1231 | dev->ctl_mute = c->value; | 1226 | dev->ctl_mute = c->value; |
1232 | saa7134_tvaudio_setmute(dev); | 1227 | saa7134_tvaudio_setmute(dev); |
1233 | break; | 1228 | break; |
1234 | case V4L2_CID_AUDIO_VOLUME: | 1229 | case V4L2_CID_AUDIO_VOLUME: |
1235 | dev->ctl_volume = c->value; | 1230 | dev->ctl_volume = c->value; |
1236 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | 1231 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); |
1237 | break; | 1232 | break; |
1238 | case V4L2_CID_PRIVATE_INVERT: | 1233 | case V4L2_CID_PRIVATE_INVERT: |
1239 | dev->ctl_invert = c->value; | 1234 | dev->ctl_invert = c->value; |
1240 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | 1235 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, |
1241 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | 1236 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); |
1242 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | 1237 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, |
1243 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | 1238 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); |
1244 | break; | 1239 | break; |
1245 | case V4L2_CID_HFLIP: | 1240 | case V4L2_CID_HFLIP: |
1246 | dev->ctl_mirror = c->value; | 1241 | dev->ctl_mirror = c->value; |
1247 | restart_overlay = 1; | 1242 | restart_overlay = 1; |
1248 | break; | 1243 | break; |
1249 | case V4L2_CID_PRIVATE_Y_EVEN: | 1244 | case V4L2_CID_PRIVATE_Y_EVEN: |
1250 | dev->ctl_y_even = c->value; | 1245 | dev->ctl_y_even = c->value; |
1251 | restart_overlay = 1; | 1246 | restart_overlay = 1; |
1252 | break; | 1247 | break; |
1253 | case V4L2_CID_PRIVATE_Y_ODD: | 1248 | case V4L2_CID_PRIVATE_Y_ODD: |
1254 | dev->ctl_y_odd = c->value; | 1249 | dev->ctl_y_odd = c->value; |
1255 | restart_overlay = 1; | 1250 | restart_overlay = 1; |
1256 | break; | 1251 | break; |
1257 | case V4L2_CID_PRIVATE_AUTOMUTE: | 1252 | case V4L2_CID_PRIVATE_AUTOMUTE: |
1258 | { | 1253 | { |
1259 | struct v4l2_priv_tun_config tda9887_cfg; | 1254 | struct v4l2_priv_tun_config tda9887_cfg; |
1260 | 1255 | ||
1261 | tda9887_cfg.tuner = TUNER_TDA9887; | 1256 | tda9887_cfg.tuner = TUNER_TDA9887; |
1262 | tda9887_cfg.priv = &dev->tda9887_conf; | 1257 | tda9887_cfg.priv = &dev->tda9887_conf; |
1263 | 1258 | ||
1264 | dev->ctl_automute = c->value; | 1259 | dev->ctl_automute = c->value; |
1265 | if (dev->tda9887_conf) { | 1260 | if (dev->tda9887_conf) { |
1266 | if (dev->ctl_automute) | 1261 | if (dev->ctl_automute) |
1267 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | 1262 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
1268 | else | 1263 | else |
1269 | dev->tda9887_conf &= ~TDA9887_AUTOMUTE; | 1264 | dev->tda9887_conf &= ~TDA9887_AUTOMUTE; |
1270 | 1265 | ||
1271 | saa_call_all(dev, tuner, s_config, &tda9887_cfg); | 1266 | saa_call_all(dev, tuner, s_config, &tda9887_cfg); |
1272 | } | 1267 | } |
1273 | break; | 1268 | break; |
1274 | } | 1269 | } |
1275 | default: | 1270 | default: |
1276 | goto error; | 1271 | goto error; |
1277 | } | 1272 | } |
1278 | if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { | 1273 | if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { |
1279 | spin_lock_irqsave(&dev->slock,flags); | 1274 | spin_lock_irqsave(&dev->slock,flags); |
1280 | stop_preview(dev,fh); | 1275 | stop_preview(dev,fh); |
1281 | start_preview(dev,fh); | 1276 | start_preview(dev,fh); |
1282 | spin_unlock_irqrestore(&dev->slock,flags); | 1277 | spin_unlock_irqrestore(&dev->slock,flags); |
1283 | } | 1278 | } |
1284 | err = 0; | 1279 | err = 0; |
1285 | 1280 | ||
1286 | error: | 1281 | error: |
1287 | mutex_unlock(&dev->lock); | 1282 | mutex_unlock(&dev->lock); |
1288 | return err; | 1283 | return err; |
1289 | } | 1284 | } |
1290 | EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); | 1285 | EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); |
1291 | 1286 | ||
1292 | static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) | 1287 | static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) |
1293 | { | 1288 | { |
1294 | struct saa7134_fh *fh = f; | 1289 | struct saa7134_fh *fh = f; |
1295 | 1290 | ||
1296 | return saa7134_s_ctrl_internal(fh->dev, fh, c); | 1291 | return saa7134_s_ctrl_internal(fh->dev, fh, c); |
1297 | } | 1292 | } |
1298 | 1293 | ||
1299 | /* ------------------------------------------------------------------ */ | 1294 | /* ------------------------------------------------------------------ */ |
1300 | 1295 | ||
1301 | static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) | 1296 | static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) |
1302 | { | 1297 | { |
1303 | struct videobuf_queue* q = NULL; | 1298 | struct videobuf_queue* q = NULL; |
1304 | 1299 | ||
1305 | switch (fh->type) { | 1300 | switch (fh->type) { |
1306 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1301 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1307 | q = &fh->cap; | 1302 | q = &fh->cap; |
1308 | break; | 1303 | break; |
1309 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1304 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
1310 | q = &fh->vbi; | 1305 | q = &fh->vbi; |
1311 | break; | 1306 | break; |
1312 | default: | 1307 | default: |
1313 | BUG(); | 1308 | BUG(); |
1314 | } | 1309 | } |
1315 | return q; | 1310 | return q; |
1316 | } | 1311 | } |
1317 | 1312 | ||
1318 | static int saa7134_resource(struct saa7134_fh *fh) | 1313 | static int saa7134_resource(struct saa7134_fh *fh) |
1319 | { | 1314 | { |
1320 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1315 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1321 | return RESOURCE_VIDEO; | 1316 | return RESOURCE_VIDEO; |
1322 | 1317 | ||
1323 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 1318 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1324 | return RESOURCE_VBI; | 1319 | return RESOURCE_VBI; |
1325 | 1320 | ||
1326 | BUG(); | 1321 | BUG(); |
1327 | return 0; | 1322 | return 0; |
1328 | } | 1323 | } |
1329 | 1324 | ||
1330 | static int video_open(struct file *file) | 1325 | static int video_open(struct file *file) |
1331 | { | 1326 | { |
1332 | int minor = video_devdata(file)->minor; | 1327 | int minor = video_devdata(file)->minor; |
1333 | struct saa7134_dev *dev; | 1328 | struct saa7134_dev *dev; |
1334 | struct saa7134_fh *fh; | 1329 | struct saa7134_fh *fh; |
1335 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1330 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1336 | int radio = 0; | 1331 | int radio = 0; |
1337 | 1332 | ||
1338 | mutex_lock(&saa7134_devlist_lock); | 1333 | mutex_lock(&saa7134_devlist_lock); |
1339 | list_for_each_entry(dev, &saa7134_devlist, devlist) { | 1334 | list_for_each_entry(dev, &saa7134_devlist, devlist) { |
1340 | if (dev->video_dev && (dev->video_dev->minor == minor)) | 1335 | if (dev->video_dev && (dev->video_dev->minor == minor)) |
1341 | goto found; | 1336 | goto found; |
1342 | if (dev->radio_dev && (dev->radio_dev->minor == minor)) { | 1337 | if (dev->radio_dev && (dev->radio_dev->minor == minor)) { |
1343 | radio = 1; | 1338 | radio = 1; |
1344 | goto found; | 1339 | goto found; |
1345 | } | 1340 | } |
1346 | if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { | 1341 | if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { |
1347 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1342 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1348 | goto found; | 1343 | goto found; |
1349 | } | 1344 | } |
1350 | } | 1345 | } |
1351 | mutex_unlock(&saa7134_devlist_lock); | 1346 | mutex_unlock(&saa7134_devlist_lock); |
1352 | return -ENODEV; | 1347 | return -ENODEV; |
1353 | 1348 | ||
1354 | found: | 1349 | found: |
1355 | mutex_unlock(&saa7134_devlist_lock); | 1350 | mutex_unlock(&saa7134_devlist_lock); |
1356 | 1351 | ||
1357 | dprintk("open minor=%d radio=%d type=%s\n",minor,radio, | 1352 | dprintk("open minor=%d radio=%d type=%s\n",minor,radio, |
1358 | v4l2_type_names[type]); | 1353 | v4l2_type_names[type]); |
1359 | 1354 | ||
1360 | /* allocate + initialize per filehandle data */ | 1355 | /* allocate + initialize per filehandle data */ |
1361 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 1356 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
1362 | if (NULL == fh) | 1357 | if (NULL == fh) |
1363 | return -ENOMEM; | 1358 | return -ENOMEM; |
1364 | 1359 | ||
1365 | file->private_data = fh; | 1360 | file->private_data = fh; |
1366 | fh->dev = dev; | 1361 | fh->dev = dev; |
1367 | fh->radio = radio; | 1362 | fh->radio = radio; |
1368 | fh->type = type; | 1363 | fh->type = type; |
1369 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | 1364 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
1370 | fh->width = 720; | 1365 | fh->width = 720; |
1371 | fh->height = 576; | 1366 | fh->height = 576; |
1372 | v4l2_prio_open(&dev->prio,&fh->prio); | 1367 | v4l2_prio_open(&dev->prio,&fh->prio); |
1373 | 1368 | ||
1374 | videobuf_queue_sg_init(&fh->cap, &video_qops, | 1369 | videobuf_queue_sg_init(&fh->cap, &video_qops, |
1375 | &dev->pci->dev, &dev->slock, | 1370 | &dev->pci->dev, &dev->slock, |
1376 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 1371 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
1377 | V4L2_FIELD_INTERLACED, | 1372 | V4L2_FIELD_INTERLACED, |
1378 | sizeof(struct saa7134_buf), | 1373 | sizeof(struct saa7134_buf), |
1379 | fh); | 1374 | fh); |
1380 | videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops, | 1375 | videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops, |
1381 | &dev->pci->dev, &dev->slock, | 1376 | &dev->pci->dev, &dev->slock, |
1382 | V4L2_BUF_TYPE_VBI_CAPTURE, | 1377 | V4L2_BUF_TYPE_VBI_CAPTURE, |
1383 | V4L2_FIELD_SEQ_TB, | 1378 | V4L2_FIELD_SEQ_TB, |
1384 | sizeof(struct saa7134_buf), | 1379 | sizeof(struct saa7134_buf), |
1385 | fh); | 1380 | fh); |
1386 | saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); | 1381 | saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); |
1387 | saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); | 1382 | saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); |
1388 | 1383 | ||
1389 | if (fh->radio) { | 1384 | if (fh->radio) { |
1390 | /* switch to radio mode */ | 1385 | /* switch to radio mode */ |
1391 | saa7134_tvaudio_setinput(dev,&card(dev).radio); | 1386 | saa7134_tvaudio_setinput(dev,&card(dev).radio); |
1392 | saa_call_all(dev, tuner, s_radio); | 1387 | saa_call_all(dev, tuner, s_radio); |
1393 | } else { | 1388 | } else { |
1394 | /* switch to video/vbi mode */ | 1389 | /* switch to video/vbi mode */ |
1395 | video_mux(dev,dev->ctl_input); | 1390 | video_mux(dev,dev->ctl_input); |
1396 | } | 1391 | } |
1397 | return 0; | 1392 | return 0; |
1398 | } | 1393 | } |
1399 | 1394 | ||
1400 | static ssize_t | 1395 | static ssize_t |
1401 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 1396 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
1402 | { | 1397 | { |
1403 | struct saa7134_fh *fh = file->private_data; | 1398 | struct saa7134_fh *fh = file->private_data; |
1404 | 1399 | ||
1405 | switch (fh->type) { | 1400 | switch (fh->type) { |
1406 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1401 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1407 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | 1402 | if (res_locked(fh->dev,RESOURCE_VIDEO)) |
1408 | return -EBUSY; | 1403 | return -EBUSY; |
1409 | return videobuf_read_one(saa7134_queue(fh), | 1404 | return videobuf_read_one(saa7134_queue(fh), |
1410 | data, count, ppos, | 1405 | data, count, ppos, |
1411 | file->f_flags & O_NONBLOCK); | 1406 | file->f_flags & O_NONBLOCK); |
1412 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1407 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
1413 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | 1408 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) |
1414 | return -EBUSY; | 1409 | return -EBUSY; |
1415 | return videobuf_read_stream(saa7134_queue(fh), | 1410 | return videobuf_read_stream(saa7134_queue(fh), |
1416 | data, count, ppos, 1, | 1411 | data, count, ppos, 1, |
1417 | file->f_flags & O_NONBLOCK); | 1412 | file->f_flags & O_NONBLOCK); |
1418 | break; | 1413 | break; |
1419 | default: | 1414 | default: |
1420 | BUG(); | 1415 | BUG(); |
1421 | return 0; | 1416 | return 0; |
1422 | } | 1417 | } |
1423 | } | 1418 | } |
1424 | 1419 | ||
1425 | static unsigned int | 1420 | static unsigned int |
1426 | video_poll(struct file *file, struct poll_table_struct *wait) | 1421 | video_poll(struct file *file, struct poll_table_struct *wait) |
1427 | { | 1422 | { |
1428 | struct saa7134_fh *fh = file->private_data; | 1423 | struct saa7134_fh *fh = file->private_data; |
1429 | struct videobuf_buffer *buf = NULL; | 1424 | struct videobuf_buffer *buf = NULL; |
1430 | 1425 | ||
1431 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) | 1426 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) |
1432 | return videobuf_poll_stream(file, &fh->vbi, wait); | 1427 | return videobuf_poll_stream(file, &fh->vbi, wait); |
1433 | 1428 | ||
1434 | if (res_check(fh,RESOURCE_VIDEO)) { | 1429 | if (res_check(fh,RESOURCE_VIDEO)) { |
1435 | if (!list_empty(&fh->cap.stream)) | 1430 | if (!list_empty(&fh->cap.stream)) |
1436 | buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); | 1431 | buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); |
1437 | } else { | 1432 | } else { |
1438 | mutex_lock(&fh->cap.vb_lock); | 1433 | mutex_lock(&fh->cap.vb_lock); |
1439 | if (UNSET == fh->cap.read_off) { | 1434 | if (UNSET == fh->cap.read_off) { |
1440 | /* need to capture a new frame */ | 1435 | /* need to capture a new frame */ |
1441 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | 1436 | if (res_locked(fh->dev,RESOURCE_VIDEO)) |
1442 | goto err; | 1437 | goto err; |
1443 | if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) | 1438 | if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) |
1444 | goto err; | 1439 | goto err; |
1445 | fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); | 1440 | fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); |
1446 | fh->cap.read_off = 0; | 1441 | fh->cap.read_off = 0; |
1447 | } | 1442 | } |
1448 | mutex_unlock(&fh->cap.vb_lock); | 1443 | mutex_unlock(&fh->cap.vb_lock); |
1449 | buf = fh->cap.read_buf; | 1444 | buf = fh->cap.read_buf; |
1450 | } | 1445 | } |
1451 | 1446 | ||
1452 | if (!buf) | 1447 | if (!buf) |
1453 | return POLLERR; | 1448 | return POLLERR; |
1454 | 1449 | ||
1455 | poll_wait(file, &buf->done, wait); | 1450 | poll_wait(file, &buf->done, wait); |
1456 | if (buf->state == VIDEOBUF_DONE || | 1451 | if (buf->state == VIDEOBUF_DONE || |
1457 | buf->state == VIDEOBUF_ERROR) | 1452 | buf->state == VIDEOBUF_ERROR) |
1458 | return POLLIN|POLLRDNORM; | 1453 | return POLLIN|POLLRDNORM; |
1459 | return 0; | 1454 | return 0; |
1460 | 1455 | ||
1461 | err: | 1456 | err: |
1462 | mutex_unlock(&fh->cap.vb_lock); | 1457 | mutex_unlock(&fh->cap.vb_lock); |
1463 | return POLLERR; | 1458 | return POLLERR; |
1464 | } | 1459 | } |
1465 | 1460 | ||
1466 | static int video_release(struct file *file) | 1461 | static int video_release(struct file *file) |
1467 | { | 1462 | { |
1468 | struct saa7134_fh *fh = file->private_data; | 1463 | struct saa7134_fh *fh = file->private_data; |
1469 | struct saa7134_dev *dev = fh->dev; | 1464 | struct saa7134_dev *dev = fh->dev; |
1470 | unsigned long flags; | 1465 | unsigned long flags; |
1471 | 1466 | ||
1472 | /* turn off overlay */ | 1467 | /* turn off overlay */ |
1473 | if (res_check(fh, RESOURCE_OVERLAY)) { | 1468 | if (res_check(fh, RESOURCE_OVERLAY)) { |
1474 | spin_lock_irqsave(&dev->slock,flags); | 1469 | spin_lock_irqsave(&dev->slock,flags); |
1475 | stop_preview(dev,fh); | 1470 | stop_preview(dev,fh); |
1476 | spin_unlock_irqrestore(&dev->slock,flags); | 1471 | spin_unlock_irqrestore(&dev->slock,flags); |
1477 | res_free(dev,fh,RESOURCE_OVERLAY); | 1472 | res_free(dev,fh,RESOURCE_OVERLAY); |
1478 | } | 1473 | } |
1479 | 1474 | ||
1480 | /* stop video capture */ | 1475 | /* stop video capture */ |
1481 | if (res_check(fh, RESOURCE_VIDEO)) { | 1476 | if (res_check(fh, RESOURCE_VIDEO)) { |
1482 | videobuf_streamoff(&fh->cap); | 1477 | videobuf_streamoff(&fh->cap); |
1483 | res_free(dev,fh,RESOURCE_VIDEO); | 1478 | res_free(dev,fh,RESOURCE_VIDEO); |
1484 | } | 1479 | } |
1485 | if (fh->cap.read_buf) { | 1480 | if (fh->cap.read_buf) { |
1486 | buffer_release(&fh->cap,fh->cap.read_buf); | 1481 | buffer_release(&fh->cap,fh->cap.read_buf); |
1487 | kfree(fh->cap.read_buf); | 1482 | kfree(fh->cap.read_buf); |
1488 | } | 1483 | } |
1489 | 1484 | ||
1490 | /* stop vbi capture */ | 1485 | /* stop vbi capture */ |
1491 | if (res_check(fh, RESOURCE_VBI)) { | 1486 | if (res_check(fh, RESOURCE_VBI)) { |
1492 | videobuf_stop(&fh->vbi); | 1487 | videobuf_stop(&fh->vbi); |
1493 | res_free(dev,fh,RESOURCE_VBI); | 1488 | res_free(dev,fh,RESOURCE_VBI); |
1494 | } | 1489 | } |
1495 | 1490 | ||
1496 | /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ | 1491 | /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ |
1497 | saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); | 1492 | saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); |
1498 | saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); | 1493 | saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); |
1499 | saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); | 1494 | saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); |
1500 | saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); | 1495 | saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); |
1501 | 1496 | ||
1502 | saa_call_all(dev, core, s_standby, 0); | 1497 | saa_call_all(dev, core, s_standby, 0); |
1503 | 1498 | ||
1504 | /* free stuff */ | 1499 | /* free stuff */ |
1505 | videobuf_mmap_free(&fh->cap); | 1500 | videobuf_mmap_free(&fh->cap); |
1506 | videobuf_mmap_free(&fh->vbi); | 1501 | videobuf_mmap_free(&fh->vbi); |
1507 | saa7134_pgtable_free(dev->pci,&fh->pt_cap); | 1502 | saa7134_pgtable_free(dev->pci,&fh->pt_cap); |
1508 | saa7134_pgtable_free(dev->pci,&fh->pt_vbi); | 1503 | saa7134_pgtable_free(dev->pci,&fh->pt_vbi); |
1509 | 1504 | ||
1510 | v4l2_prio_close(&dev->prio,&fh->prio); | 1505 | v4l2_prio_close(&dev->prio,&fh->prio); |
1511 | file->private_data = NULL; | 1506 | file->private_data = NULL; |
1512 | kfree(fh); | 1507 | kfree(fh); |
1513 | return 0; | 1508 | return 0; |
1514 | } | 1509 | } |
1515 | 1510 | ||
1516 | static int video_mmap(struct file *file, struct vm_area_struct * vma) | 1511 | static int video_mmap(struct file *file, struct vm_area_struct * vma) |
1517 | { | 1512 | { |
1518 | struct saa7134_fh *fh = file->private_data; | 1513 | struct saa7134_fh *fh = file->private_data; |
1519 | 1514 | ||
1520 | return videobuf_mmap_mapper(saa7134_queue(fh), vma); | 1515 | return videobuf_mmap_mapper(saa7134_queue(fh), vma); |
1521 | } | 1516 | } |
1522 | 1517 | ||
1523 | /* ------------------------------------------------------------------ */ | 1518 | /* ------------------------------------------------------------------ */ |
1524 | 1519 | ||
1525 | static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, | 1520 | static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, |
1526 | struct v4l2_format *f) | 1521 | struct v4l2_format *f) |
1527 | { | 1522 | { |
1528 | struct saa7134_fh *fh = priv; | 1523 | struct saa7134_fh *fh = priv; |
1529 | struct saa7134_dev *dev = fh->dev; | 1524 | struct saa7134_dev *dev = fh->dev; |
1530 | struct saa7134_tvnorm *norm = dev->tvnorm; | 1525 | struct saa7134_tvnorm *norm = dev->tvnorm; |
1531 | 1526 | ||
1532 | f->fmt.vbi.sampling_rate = 6750000 * 4; | 1527 | f->fmt.vbi.sampling_rate = 6750000 * 4; |
1533 | f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; | 1528 | f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; |
1534 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | 1529 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; |
1535 | f->fmt.vbi.offset = 64 * 4; | 1530 | f->fmt.vbi.offset = 64 * 4; |
1536 | f->fmt.vbi.start[0] = norm->vbi_v_start_0; | 1531 | f->fmt.vbi.start[0] = norm->vbi_v_start_0; |
1537 | f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; | 1532 | f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; |
1538 | f->fmt.vbi.start[1] = norm->vbi_v_start_1; | 1533 | f->fmt.vbi.start[1] = norm->vbi_v_start_1; |
1539 | f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; | 1534 | f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; |
1540 | f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ | 1535 | f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ |
1541 | 1536 | ||
1542 | return 0; | 1537 | return 0; |
1543 | } | 1538 | } |
1544 | 1539 | ||
1545 | static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, | 1540 | static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, |
1546 | struct v4l2_format *f) | 1541 | struct v4l2_format *f) |
1547 | { | 1542 | { |
1548 | struct saa7134_fh *fh = priv; | 1543 | struct saa7134_fh *fh = priv; |
1549 | 1544 | ||
1550 | f->fmt.pix.width = fh->width; | 1545 | f->fmt.pix.width = fh->width; |
1551 | f->fmt.pix.height = fh->height; | 1546 | f->fmt.pix.height = fh->height; |
1552 | f->fmt.pix.field = fh->cap.field; | 1547 | f->fmt.pix.field = fh->cap.field; |
1553 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | 1548 | f->fmt.pix.pixelformat = fh->fmt->fourcc; |
1554 | f->fmt.pix.bytesperline = | 1549 | f->fmt.pix.bytesperline = |
1555 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | 1550 | (f->fmt.pix.width * fh->fmt->depth) >> 3; |
1556 | f->fmt.pix.sizeimage = | 1551 | f->fmt.pix.sizeimage = |
1557 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1552 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1558 | return 0; | 1553 | return 0; |
1559 | } | 1554 | } |
1560 | 1555 | ||
1561 | static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, | 1556 | static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, |
1562 | struct v4l2_format *f) | 1557 | struct v4l2_format *f) |
1563 | { | 1558 | { |
1564 | struct saa7134_fh *fh = priv; | 1559 | struct saa7134_fh *fh = priv; |
1565 | 1560 | ||
1566 | if (saa7134_no_overlay > 0) { | 1561 | if (saa7134_no_overlay > 0) { |
1567 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); | 1562 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); |
1568 | return -EINVAL; | 1563 | return -EINVAL; |
1569 | } | 1564 | } |
1570 | f->fmt.win = fh->win; | 1565 | f->fmt.win = fh->win; |
1571 | 1566 | ||
1572 | return 0; | 1567 | return 0; |
1573 | } | 1568 | } |
1574 | 1569 | ||
1575 | static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, | 1570 | static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, |
1576 | struct v4l2_format *f) | 1571 | struct v4l2_format *f) |
1577 | { | 1572 | { |
1578 | struct saa7134_fh *fh = priv; | 1573 | struct saa7134_fh *fh = priv; |
1579 | struct saa7134_dev *dev = fh->dev; | 1574 | struct saa7134_dev *dev = fh->dev; |
1580 | struct saa7134_format *fmt; | 1575 | struct saa7134_format *fmt; |
1581 | enum v4l2_field field; | 1576 | enum v4l2_field field; |
1582 | unsigned int maxw, maxh; | 1577 | unsigned int maxw, maxh; |
1583 | 1578 | ||
1584 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1579 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1585 | if (NULL == fmt) | 1580 | if (NULL == fmt) |
1586 | return -EINVAL; | 1581 | return -EINVAL; |
1587 | 1582 | ||
1588 | field = f->fmt.pix.field; | 1583 | field = f->fmt.pix.field; |
1589 | maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); | 1584 | maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); |
1590 | maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); | 1585 | maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); |
1591 | 1586 | ||
1592 | if (V4L2_FIELD_ANY == field) { | 1587 | if (V4L2_FIELD_ANY == field) { |
1593 | field = (f->fmt.pix.height > maxh/2) | 1588 | field = (f->fmt.pix.height > maxh/2) |
1594 | ? V4L2_FIELD_INTERLACED | 1589 | ? V4L2_FIELD_INTERLACED |
1595 | : V4L2_FIELD_BOTTOM; | 1590 | : V4L2_FIELD_BOTTOM; |
1596 | } | 1591 | } |
1597 | switch (field) { | 1592 | switch (field) { |
1598 | case V4L2_FIELD_TOP: | 1593 | case V4L2_FIELD_TOP: |
1599 | case V4L2_FIELD_BOTTOM: | 1594 | case V4L2_FIELD_BOTTOM: |
1600 | maxh = maxh / 2; | 1595 | maxh = maxh / 2; |
1601 | break; | 1596 | break; |
1602 | case V4L2_FIELD_INTERLACED: | 1597 | case V4L2_FIELD_INTERLACED: |
1603 | break; | 1598 | break; |
1604 | default: | 1599 | default: |
1605 | return -EINVAL; | 1600 | return -EINVAL; |
1606 | } | 1601 | } |
1607 | 1602 | ||
1608 | f->fmt.pix.field = field; | 1603 | f->fmt.pix.field = field; |
1609 | if (f->fmt.pix.width < 48) | 1604 | if (f->fmt.pix.width < 48) |
1610 | f->fmt.pix.width = 48; | 1605 | f->fmt.pix.width = 48; |
1611 | if (f->fmt.pix.height < 32) | 1606 | if (f->fmt.pix.height < 32) |
1612 | f->fmt.pix.height = 32; | 1607 | f->fmt.pix.height = 32; |
1613 | if (f->fmt.pix.width > maxw) | 1608 | if (f->fmt.pix.width > maxw) |
1614 | f->fmt.pix.width = maxw; | 1609 | f->fmt.pix.width = maxw; |
1615 | if (f->fmt.pix.height > maxh) | 1610 | if (f->fmt.pix.height > maxh) |
1616 | f->fmt.pix.height = maxh; | 1611 | f->fmt.pix.height = maxh; |
1617 | f->fmt.pix.width &= ~0x03; | 1612 | f->fmt.pix.width &= ~0x03; |
1618 | f->fmt.pix.bytesperline = | 1613 | f->fmt.pix.bytesperline = |
1619 | (f->fmt.pix.width * fmt->depth) >> 3; | 1614 | (f->fmt.pix.width * fmt->depth) >> 3; |
1620 | f->fmt.pix.sizeimage = | 1615 | f->fmt.pix.sizeimage = |
1621 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1616 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1622 | 1617 | ||
1623 | return 0; | 1618 | return 0; |
1624 | } | 1619 | } |
1625 | 1620 | ||
1626 | static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, | 1621 | static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, |
1627 | struct v4l2_format *f) | 1622 | struct v4l2_format *f) |
1628 | { | 1623 | { |
1629 | struct saa7134_fh *fh = priv; | 1624 | struct saa7134_fh *fh = priv; |
1630 | struct saa7134_dev *dev = fh->dev; | 1625 | struct saa7134_dev *dev = fh->dev; |
1631 | 1626 | ||
1632 | if (saa7134_no_overlay > 0) { | 1627 | if (saa7134_no_overlay > 0) { |
1633 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); | 1628 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); |
1634 | return -EINVAL; | 1629 | return -EINVAL; |
1635 | } | 1630 | } |
1636 | 1631 | ||
1637 | return verify_preview(dev, &f->fmt.win); | 1632 | return verify_preview(dev, &f->fmt.win); |
1638 | } | 1633 | } |
1639 | 1634 | ||
1640 | static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, | 1635 | static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, |
1641 | struct v4l2_format *f) | 1636 | struct v4l2_format *f) |
1642 | { | 1637 | { |
1643 | struct saa7134_fh *fh = priv; | 1638 | struct saa7134_fh *fh = priv; |
1644 | int err; | 1639 | int err; |
1645 | 1640 | ||
1646 | err = saa7134_try_fmt_vid_cap(file, priv, f); | 1641 | err = saa7134_try_fmt_vid_cap(file, priv, f); |
1647 | if (0 != err) | 1642 | if (0 != err) |
1648 | return err; | 1643 | return err; |
1649 | 1644 | ||
1650 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1645 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1651 | fh->width = f->fmt.pix.width; | 1646 | fh->width = f->fmt.pix.width; |
1652 | fh->height = f->fmt.pix.height; | 1647 | fh->height = f->fmt.pix.height; |
1653 | fh->cap.field = f->fmt.pix.field; | 1648 | fh->cap.field = f->fmt.pix.field; |
1654 | return 0; | 1649 | return 0; |
1655 | } | 1650 | } |
1656 | 1651 | ||
1657 | static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, | 1652 | static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, |
1658 | struct v4l2_format *f) | 1653 | struct v4l2_format *f) |
1659 | { | 1654 | { |
1660 | struct saa7134_fh *fh = priv; | 1655 | struct saa7134_fh *fh = priv; |
1661 | struct saa7134_dev *dev = fh->dev; | 1656 | struct saa7134_dev *dev = fh->dev; |
1662 | int err; | 1657 | int err; |
1663 | unsigned long flags; | 1658 | unsigned long flags; |
1664 | 1659 | ||
1665 | if (saa7134_no_overlay > 0) { | 1660 | if (saa7134_no_overlay > 0) { |
1666 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); | 1661 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); |
1667 | return -EINVAL; | 1662 | return -EINVAL; |
1668 | } | 1663 | } |
1669 | err = verify_preview(dev, &f->fmt.win); | 1664 | err = verify_preview(dev, &f->fmt.win); |
1670 | if (0 != err) | 1665 | if (0 != err) |
1671 | return err; | 1666 | return err; |
1672 | 1667 | ||
1673 | mutex_lock(&dev->lock); | 1668 | mutex_lock(&dev->lock); |
1674 | 1669 | ||
1675 | fh->win = f->fmt.win; | 1670 | fh->win = f->fmt.win; |
1676 | fh->nclips = f->fmt.win.clipcount; | 1671 | fh->nclips = f->fmt.win.clipcount; |
1677 | 1672 | ||
1678 | if (fh->nclips > 8) | 1673 | if (fh->nclips > 8) |
1679 | fh->nclips = 8; | 1674 | fh->nclips = 8; |
1680 | 1675 | ||
1681 | if (copy_from_user(fh->clips, f->fmt.win.clips, | 1676 | if (copy_from_user(fh->clips, f->fmt.win.clips, |
1682 | sizeof(struct v4l2_clip)*fh->nclips)) { | 1677 | sizeof(struct v4l2_clip)*fh->nclips)) { |
1683 | mutex_unlock(&dev->lock); | 1678 | mutex_unlock(&dev->lock); |
1684 | return -EFAULT; | 1679 | return -EFAULT; |
1685 | } | 1680 | } |
1686 | 1681 | ||
1687 | if (res_check(fh, RESOURCE_OVERLAY)) { | 1682 | if (res_check(fh, RESOURCE_OVERLAY)) { |
1688 | spin_lock_irqsave(&dev->slock, flags); | 1683 | spin_lock_irqsave(&dev->slock, flags); |
1689 | stop_preview(dev, fh); | 1684 | stop_preview(dev, fh); |
1690 | start_preview(dev, fh); | 1685 | start_preview(dev, fh); |
1691 | spin_unlock_irqrestore(&dev->slock, flags); | 1686 | spin_unlock_irqrestore(&dev->slock, flags); |
1692 | } | 1687 | } |
1693 | 1688 | ||
1694 | mutex_unlock(&dev->lock); | 1689 | mutex_unlock(&dev->lock); |
1695 | return 0; | 1690 | return 0; |
1696 | } | 1691 | } |
1697 | 1692 | ||
1698 | int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) | 1693 | int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) |
1699 | { | 1694 | { |
1700 | const struct v4l2_queryctrl *ctrl; | 1695 | const struct v4l2_queryctrl *ctrl; |
1701 | 1696 | ||
1702 | if ((c->id < V4L2_CID_BASE || | 1697 | if ((c->id < V4L2_CID_BASE || |
1703 | c->id >= V4L2_CID_LASTP1) && | 1698 | c->id >= V4L2_CID_LASTP1) && |
1704 | (c->id < V4L2_CID_PRIVATE_BASE || | 1699 | (c->id < V4L2_CID_PRIVATE_BASE || |
1705 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | 1700 | c->id >= V4L2_CID_PRIVATE_LASTP1)) |
1706 | return -EINVAL; | 1701 | return -EINVAL; |
1707 | ctrl = ctrl_by_id(c->id); | 1702 | ctrl = ctrl_by_id(c->id); |
1708 | *c = (NULL != ctrl) ? *ctrl : no_ctrl; | 1703 | *c = (NULL != ctrl) ? *ctrl : no_ctrl; |
1709 | return 0; | 1704 | return 0; |
1710 | } | 1705 | } |
1711 | EXPORT_SYMBOL_GPL(saa7134_queryctrl); | 1706 | EXPORT_SYMBOL_GPL(saa7134_queryctrl); |
1712 | 1707 | ||
1713 | static int saa7134_enum_input(struct file *file, void *priv, | 1708 | static int saa7134_enum_input(struct file *file, void *priv, |
1714 | struct v4l2_input *i) | 1709 | struct v4l2_input *i) |
1715 | { | 1710 | { |
1716 | struct saa7134_fh *fh = priv; | 1711 | struct saa7134_fh *fh = priv; |
1717 | struct saa7134_dev *dev = fh->dev; | 1712 | struct saa7134_dev *dev = fh->dev; |
1718 | unsigned int n; | 1713 | unsigned int n; |
1719 | 1714 | ||
1720 | n = i->index; | 1715 | n = i->index; |
1721 | if (n >= SAA7134_INPUT_MAX) | 1716 | if (n >= SAA7134_INPUT_MAX) |
1722 | return -EINVAL; | 1717 | return -EINVAL; |
1723 | if (NULL == card_in(dev, i->index).name) | 1718 | if (NULL == card_in(dev, i->index).name) |
1724 | return -EINVAL; | 1719 | return -EINVAL; |
1725 | memset(i, 0, sizeof(*i)); | 1720 | memset(i, 0, sizeof(*i)); |
1726 | i->index = n; | 1721 | i->index = n; |
1727 | i->type = V4L2_INPUT_TYPE_CAMERA; | 1722 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1728 | strcpy(i->name, card_in(dev, n).name); | 1723 | strcpy(i->name, card_in(dev, n).name); |
1729 | if (card_in(dev, n).tv) | 1724 | if (card_in(dev, n).tv) |
1730 | i->type = V4L2_INPUT_TYPE_TUNER; | 1725 | i->type = V4L2_INPUT_TYPE_TUNER; |
1731 | i->audioset = 1; | 1726 | i->audioset = 1; |
1732 | if (n == dev->ctl_input) { | 1727 | if (n == dev->ctl_input) { |
1733 | int v1 = saa_readb(SAA7134_STATUS_VIDEO1); | 1728 | int v1 = saa_readb(SAA7134_STATUS_VIDEO1); |
1734 | int v2 = saa_readb(SAA7134_STATUS_VIDEO2); | 1729 | int v2 = saa_readb(SAA7134_STATUS_VIDEO2); |
1735 | 1730 | ||
1736 | if (0 != (v1 & 0x40)) | 1731 | if (0 != (v1 & 0x40)) |
1737 | i->status |= V4L2_IN_ST_NO_H_LOCK; | 1732 | i->status |= V4L2_IN_ST_NO_H_LOCK; |
1738 | if (0 != (v2 & 0x40)) | 1733 | if (0 != (v2 & 0x40)) |
1739 | i->status |= V4L2_IN_ST_NO_SYNC; | 1734 | i->status |= V4L2_IN_ST_NO_SYNC; |
1740 | if (0 != (v2 & 0x0e)) | 1735 | if (0 != (v2 & 0x0e)) |
1741 | i->status |= V4L2_IN_ST_MACROVISION; | 1736 | i->status |= V4L2_IN_ST_MACROVISION; |
1742 | } | 1737 | } |
1743 | i->std = SAA7134_NORMS; | 1738 | i->std = SAA7134_NORMS; |
1744 | return 0; | 1739 | return 0; |
1745 | } | 1740 | } |
1746 | 1741 | ||
1747 | static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) | 1742 | static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) |
1748 | { | 1743 | { |
1749 | struct saa7134_fh *fh = priv; | 1744 | struct saa7134_fh *fh = priv; |
1750 | struct saa7134_dev *dev = fh->dev; | 1745 | struct saa7134_dev *dev = fh->dev; |
1751 | 1746 | ||
1752 | *i = dev->ctl_input; | 1747 | *i = dev->ctl_input; |
1753 | return 0; | 1748 | return 0; |
1754 | } | 1749 | } |
1755 | 1750 | ||
1756 | static int saa7134_s_input(struct file *file, void *priv, unsigned int i) | 1751 | static int saa7134_s_input(struct file *file, void *priv, unsigned int i) |
1757 | { | 1752 | { |
1758 | struct saa7134_fh *fh = priv; | 1753 | struct saa7134_fh *fh = priv; |
1759 | struct saa7134_dev *dev = fh->dev; | 1754 | struct saa7134_dev *dev = fh->dev; |
1760 | int err; | 1755 | int err; |
1761 | 1756 | ||
1762 | err = v4l2_prio_check(&dev->prio, &fh->prio); | 1757 | err = v4l2_prio_check(&dev->prio, &fh->prio); |
1763 | if (0 != err) | 1758 | if (0 != err) |
1764 | return err; | 1759 | return err; |
1765 | 1760 | ||
1766 | if (i < 0 || i >= SAA7134_INPUT_MAX) | 1761 | if (i < 0 || i >= SAA7134_INPUT_MAX) |
1767 | return -EINVAL; | 1762 | return -EINVAL; |
1768 | if (NULL == card_in(dev, i).name) | 1763 | if (NULL == card_in(dev, i).name) |
1769 | return -EINVAL; | 1764 | return -EINVAL; |
1770 | mutex_lock(&dev->lock); | 1765 | mutex_lock(&dev->lock); |
1771 | video_mux(dev, i); | 1766 | video_mux(dev, i); |
1772 | mutex_unlock(&dev->lock); | 1767 | mutex_unlock(&dev->lock); |
1773 | return 0; | 1768 | return 0; |
1774 | } | 1769 | } |
1775 | 1770 | ||
1776 | static int saa7134_querycap(struct file *file, void *priv, | 1771 | static int saa7134_querycap(struct file *file, void *priv, |
1777 | struct v4l2_capability *cap) | 1772 | struct v4l2_capability *cap) |
1778 | { | 1773 | { |
1779 | struct saa7134_fh *fh = priv; | 1774 | struct saa7134_fh *fh = priv; |
1780 | struct saa7134_dev *dev = fh->dev; | 1775 | struct saa7134_dev *dev = fh->dev; |
1781 | 1776 | ||
1782 | unsigned int tuner_type = dev->tuner_type; | 1777 | unsigned int tuner_type = dev->tuner_type; |
1783 | 1778 | ||
1784 | strcpy(cap->driver, "saa7134"); | 1779 | strcpy(cap->driver, "saa7134"); |
1785 | strlcpy(cap->card, saa7134_boards[dev->board].name, | 1780 | strlcpy(cap->card, saa7134_boards[dev->board].name, |
1786 | sizeof(cap->card)); | 1781 | sizeof(cap->card)); |
1787 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | 1782 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); |
1788 | cap->version = SAA7134_VERSION_CODE; | 1783 | cap->version = SAA7134_VERSION_CODE; |
1789 | cap->capabilities = | 1784 | cap->capabilities = |
1790 | V4L2_CAP_VIDEO_CAPTURE | | 1785 | V4L2_CAP_VIDEO_CAPTURE | |
1791 | V4L2_CAP_VBI_CAPTURE | | 1786 | V4L2_CAP_VBI_CAPTURE | |
1792 | V4L2_CAP_READWRITE | | 1787 | V4L2_CAP_READWRITE | |
1793 | V4L2_CAP_STREAMING | | 1788 | V4L2_CAP_STREAMING | |
1794 | V4L2_CAP_TUNER; | 1789 | V4L2_CAP_TUNER; |
1795 | if (saa7134_no_overlay <= 0) | 1790 | if (saa7134_no_overlay <= 0) |
1796 | cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; | 1791 | cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; |
1797 | 1792 | ||
1798 | if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) | 1793 | if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) |
1799 | cap->capabilities &= ~V4L2_CAP_TUNER; | 1794 | cap->capabilities &= ~V4L2_CAP_TUNER; |
1800 | return 0; | 1795 | return 0; |
1801 | } | 1796 | } |
1802 | 1797 | ||
1803 | int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id) | 1798 | int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id) |
1804 | { | 1799 | { |
1805 | unsigned long flags; | 1800 | unsigned long flags; |
1806 | unsigned int i; | 1801 | unsigned int i; |
1807 | v4l2_std_id fixup; | 1802 | v4l2_std_id fixup; |
1808 | int err; | 1803 | int err; |
1809 | 1804 | ||
1810 | /* When called from the empress code fh == NULL. | 1805 | /* When called from the empress code fh == NULL. |
1811 | That needs to be fixed somehow, but for now this is | 1806 | That needs to be fixed somehow, but for now this is |
1812 | good enough. */ | 1807 | good enough. */ |
1813 | if (fh) { | 1808 | if (fh) { |
1814 | err = v4l2_prio_check(&dev->prio, &fh->prio); | 1809 | err = v4l2_prio_check(&dev->prio, &fh->prio); |
1815 | if (0 != err) | 1810 | if (0 != err) |
1816 | return err; | 1811 | return err; |
1817 | } else if (res_locked(dev, RESOURCE_OVERLAY)) { | 1812 | } else if (res_locked(dev, RESOURCE_OVERLAY)) { |
1818 | /* Don't change the std from the mpeg device | 1813 | /* Don't change the std from the mpeg device |
1819 | if overlay is active. */ | 1814 | if overlay is active. */ |
1820 | return -EBUSY; | 1815 | return -EBUSY; |
1821 | } | 1816 | } |
1822 | 1817 | ||
1823 | for (i = 0; i < TVNORMS; i++) | 1818 | for (i = 0; i < TVNORMS; i++) |
1824 | if (*id == tvnorms[i].id) | 1819 | if (*id == tvnorms[i].id) |
1825 | break; | 1820 | break; |
1826 | 1821 | ||
1827 | if (i == TVNORMS) | 1822 | if (i == TVNORMS) |
1828 | for (i = 0; i < TVNORMS; i++) | 1823 | for (i = 0; i < TVNORMS; i++) |
1829 | if (*id & tvnorms[i].id) | 1824 | if (*id & tvnorms[i].id) |
1830 | break; | 1825 | break; |
1831 | if (i == TVNORMS) | 1826 | if (i == TVNORMS) |
1832 | return -EINVAL; | 1827 | return -EINVAL; |
1833 | 1828 | ||
1834 | if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { | 1829 | if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { |
1835 | if (secam[0] == 'L' || secam[0] == 'l') { | 1830 | if (secam[0] == 'L' || secam[0] == 'l') { |
1836 | if (secam[1] == 'C' || secam[1] == 'c') | 1831 | if (secam[1] == 'C' || secam[1] == 'c') |
1837 | fixup = V4L2_STD_SECAM_LC; | 1832 | fixup = V4L2_STD_SECAM_LC; |
1838 | else | 1833 | else |
1839 | fixup = V4L2_STD_SECAM_L; | 1834 | fixup = V4L2_STD_SECAM_L; |
1840 | } else { | 1835 | } else { |
1841 | if (secam[0] == 'D' || secam[0] == 'd') | 1836 | if (secam[0] == 'D' || secam[0] == 'd') |
1842 | fixup = V4L2_STD_SECAM_DK; | 1837 | fixup = V4L2_STD_SECAM_DK; |
1843 | else | 1838 | else |
1844 | fixup = V4L2_STD_SECAM; | 1839 | fixup = V4L2_STD_SECAM; |
1845 | } | 1840 | } |
1846 | for (i = 0; i < TVNORMS; i++) | 1841 | for (i = 0; i < TVNORMS; i++) |
1847 | if (fixup == tvnorms[i].id) | 1842 | if (fixup == tvnorms[i].id) |
1848 | break; | 1843 | break; |
1849 | } | 1844 | } |
1850 | 1845 | ||
1851 | *id = tvnorms[i].id; | 1846 | *id = tvnorms[i].id; |
1852 | 1847 | ||
1853 | mutex_lock(&dev->lock); | 1848 | mutex_lock(&dev->lock); |
1854 | if (fh && res_check(fh, RESOURCE_OVERLAY)) { | 1849 | if (fh && res_check(fh, RESOURCE_OVERLAY)) { |
1855 | spin_lock_irqsave(&dev->slock, flags); | 1850 | spin_lock_irqsave(&dev->slock, flags); |
1856 | stop_preview(dev, fh); | 1851 | stop_preview(dev, fh); |
1857 | spin_unlock_irqrestore(&dev->slock, flags); | 1852 | spin_unlock_irqrestore(&dev->slock, flags); |
1858 | 1853 | ||
1859 | set_tvnorm(dev, &tvnorms[i]); | 1854 | set_tvnorm(dev, &tvnorms[i]); |
1860 | 1855 | ||
1861 | spin_lock_irqsave(&dev->slock, flags); | 1856 | spin_lock_irqsave(&dev->slock, flags); |
1862 | start_preview(dev, fh); | 1857 | start_preview(dev, fh); |
1863 | spin_unlock_irqrestore(&dev->slock, flags); | 1858 | spin_unlock_irqrestore(&dev->slock, flags); |
1864 | } else | 1859 | } else |
1865 | set_tvnorm(dev, &tvnorms[i]); | 1860 | set_tvnorm(dev, &tvnorms[i]); |
1866 | 1861 | ||
1867 | saa7134_tvaudio_do_scan(dev); | 1862 | saa7134_tvaudio_do_scan(dev); |
1868 | mutex_unlock(&dev->lock); | 1863 | mutex_unlock(&dev->lock); |
1869 | return 0; | 1864 | return 0; |
1870 | } | 1865 | } |
1871 | EXPORT_SYMBOL_GPL(saa7134_s_std_internal); | 1866 | EXPORT_SYMBOL_GPL(saa7134_s_std_internal); |
1872 | 1867 | ||
1873 | static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) | 1868 | static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) |
1874 | { | 1869 | { |
1875 | struct saa7134_fh *fh = priv; | 1870 | struct saa7134_fh *fh = priv; |
1876 | 1871 | ||
1877 | return saa7134_s_std_internal(fh->dev, fh, id); | 1872 | return saa7134_s_std_internal(fh->dev, fh, id); |
1878 | } | 1873 | } |
1879 | 1874 | ||
1880 | static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) | 1875 | static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) |
1881 | { | 1876 | { |
1882 | struct saa7134_fh *fh = priv; | 1877 | struct saa7134_fh *fh = priv; |
1883 | struct saa7134_dev *dev = fh->dev; | 1878 | struct saa7134_dev *dev = fh->dev; |
1884 | 1879 | ||
1885 | *id = dev->tvnorm->id; | 1880 | *id = dev->tvnorm->id; |
1886 | return 0; | 1881 | return 0; |
1887 | } | 1882 | } |
1888 | 1883 | ||
1889 | static int saa7134_cropcap(struct file *file, void *priv, | 1884 | static int saa7134_cropcap(struct file *file, void *priv, |
1890 | struct v4l2_cropcap *cap) | 1885 | struct v4l2_cropcap *cap) |
1891 | { | 1886 | { |
1892 | struct saa7134_fh *fh = priv; | 1887 | struct saa7134_fh *fh = priv; |
1893 | struct saa7134_dev *dev = fh->dev; | 1888 | struct saa7134_dev *dev = fh->dev; |
1894 | 1889 | ||
1895 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1890 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1896 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1891 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1897 | return -EINVAL; | 1892 | return -EINVAL; |
1898 | cap->bounds = dev->crop_bounds; | 1893 | cap->bounds = dev->crop_bounds; |
1899 | cap->defrect = dev->crop_defrect; | 1894 | cap->defrect = dev->crop_defrect; |
1900 | cap->pixelaspect.numerator = 1; | 1895 | cap->pixelaspect.numerator = 1; |
1901 | cap->pixelaspect.denominator = 1; | 1896 | cap->pixelaspect.denominator = 1; |
1902 | if (dev->tvnorm->id & V4L2_STD_525_60) { | 1897 | if (dev->tvnorm->id & V4L2_STD_525_60) { |
1903 | cap->pixelaspect.numerator = 11; | 1898 | cap->pixelaspect.numerator = 11; |
1904 | cap->pixelaspect.denominator = 10; | 1899 | cap->pixelaspect.denominator = 10; |
1905 | } | 1900 | } |
1906 | if (dev->tvnorm->id & V4L2_STD_625_50) { | 1901 | if (dev->tvnorm->id & V4L2_STD_625_50) { |
1907 | cap->pixelaspect.numerator = 54; | 1902 | cap->pixelaspect.numerator = 54; |
1908 | cap->pixelaspect.denominator = 59; | 1903 | cap->pixelaspect.denominator = 59; |
1909 | } | 1904 | } |
1910 | return 0; | 1905 | return 0; |
1911 | } | 1906 | } |
1912 | 1907 | ||
1913 | static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | 1908 | static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) |
1914 | { | 1909 | { |
1915 | struct saa7134_fh *fh = f; | 1910 | struct saa7134_fh *fh = f; |
1916 | struct saa7134_dev *dev = fh->dev; | 1911 | struct saa7134_dev *dev = fh->dev; |
1917 | 1912 | ||
1918 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1913 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1919 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1914 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1920 | return -EINVAL; | 1915 | return -EINVAL; |
1921 | crop->c = dev->crop_current; | 1916 | crop->c = dev->crop_current; |
1922 | return 0; | 1917 | return 0; |
1923 | } | 1918 | } |
1924 | 1919 | ||
1925 | static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) | 1920 | static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) |
1926 | { | 1921 | { |
1927 | struct saa7134_fh *fh = f; | 1922 | struct saa7134_fh *fh = f; |
1928 | struct saa7134_dev *dev = fh->dev; | 1923 | struct saa7134_dev *dev = fh->dev; |
1929 | struct v4l2_rect *b = &dev->crop_bounds; | 1924 | struct v4l2_rect *b = &dev->crop_bounds; |
1930 | 1925 | ||
1931 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1926 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1932 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1927 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1933 | return -EINVAL; | 1928 | return -EINVAL; |
1934 | if (crop->c.height < 0) | 1929 | if (crop->c.height < 0) |
1935 | return -EINVAL; | 1930 | return -EINVAL; |
1936 | if (crop->c.width < 0) | 1931 | if (crop->c.width < 0) |
1937 | return -EINVAL; | 1932 | return -EINVAL; |
1938 | 1933 | ||
1939 | if (res_locked(fh->dev, RESOURCE_OVERLAY)) | 1934 | if (res_locked(fh->dev, RESOURCE_OVERLAY)) |
1940 | return -EBUSY; | 1935 | return -EBUSY; |
1941 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | 1936 | if (res_locked(fh->dev, RESOURCE_VIDEO)) |
1942 | return -EBUSY; | 1937 | return -EBUSY; |
1943 | 1938 | ||
1944 | if (crop->c.top < b->top) | 1939 | if (crop->c.top < b->top) |
1945 | crop->c.top = b->top; | 1940 | crop->c.top = b->top; |
1946 | if (crop->c.top > b->top + b->height) | 1941 | if (crop->c.top > b->top + b->height) |
1947 | crop->c.top = b->top + b->height; | 1942 | crop->c.top = b->top + b->height; |
1948 | if (crop->c.height > b->top - crop->c.top + b->height) | 1943 | if (crop->c.height > b->top - crop->c.top + b->height) |
1949 | crop->c.height = b->top - crop->c.top + b->height; | 1944 | crop->c.height = b->top - crop->c.top + b->height; |
1950 | 1945 | ||
1951 | if (crop->c.left < b->left) | 1946 | if (crop->c.left < b->left) |
1952 | crop->c.left = b->left; | 1947 | crop->c.left = b->left; |
1953 | if (crop->c.left > b->left + b->width) | 1948 | if (crop->c.left > b->left + b->width) |
1954 | crop->c.left = b->left + b->width; | 1949 | crop->c.left = b->left + b->width; |
1955 | if (crop->c.width > b->left - crop->c.left + b->width) | 1950 | if (crop->c.width > b->left - crop->c.left + b->width) |
1956 | crop->c.width = b->left - crop->c.left + b->width; | 1951 | crop->c.width = b->left - crop->c.left + b->width; |
1957 | 1952 | ||
1958 | dev->crop_current = crop->c; | 1953 | dev->crop_current = crop->c; |
1959 | return 0; | 1954 | return 0; |
1960 | } | 1955 | } |
1961 | 1956 | ||
1962 | static int saa7134_g_tuner(struct file *file, void *priv, | 1957 | static int saa7134_g_tuner(struct file *file, void *priv, |
1963 | struct v4l2_tuner *t) | 1958 | struct v4l2_tuner *t) |
1964 | { | 1959 | { |
1965 | struct saa7134_fh *fh = priv; | 1960 | struct saa7134_fh *fh = priv; |
1966 | struct saa7134_dev *dev = fh->dev; | 1961 | struct saa7134_dev *dev = fh->dev; |
1967 | int n; | 1962 | int n; |
1968 | 1963 | ||
1969 | if (0 != t->index) | 1964 | if (0 != t->index) |
1970 | return -EINVAL; | 1965 | return -EINVAL; |
1971 | memset(t, 0, sizeof(*t)); | 1966 | memset(t, 0, sizeof(*t)); |
1972 | for (n = 0; n < SAA7134_INPUT_MAX; n++) | 1967 | for (n = 0; n < SAA7134_INPUT_MAX; n++) |
1973 | if (card_in(dev, n).tv) | 1968 | if (card_in(dev, n).tv) |
1974 | break; | 1969 | break; |
1975 | if (NULL != card_in(dev, n).name) { | 1970 | if (NULL != card_in(dev, n).name) { |
1976 | strcpy(t->name, "Television"); | 1971 | strcpy(t->name, "Television"); |
1977 | t->type = V4L2_TUNER_ANALOG_TV; | 1972 | t->type = V4L2_TUNER_ANALOG_TV; |
1978 | t->capability = V4L2_TUNER_CAP_NORM | | 1973 | t->capability = V4L2_TUNER_CAP_NORM | |
1979 | V4L2_TUNER_CAP_STEREO | | 1974 | V4L2_TUNER_CAP_STEREO | |
1980 | V4L2_TUNER_CAP_LANG1 | | 1975 | V4L2_TUNER_CAP_LANG1 | |
1981 | V4L2_TUNER_CAP_LANG2; | 1976 | V4L2_TUNER_CAP_LANG2; |
1982 | t->rangehigh = 0xffffffffUL; | 1977 | t->rangehigh = 0xffffffffUL; |
1983 | t->rxsubchans = saa7134_tvaudio_getstereo(dev); | 1978 | t->rxsubchans = saa7134_tvaudio_getstereo(dev); |
1984 | t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); | 1979 | t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); |
1985 | } | 1980 | } |
1986 | if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) | 1981 | if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) |
1987 | t->signal = 0xffff; | 1982 | t->signal = 0xffff; |
1988 | return 0; | 1983 | return 0; |
1989 | } | 1984 | } |
1990 | 1985 | ||
1991 | static int saa7134_s_tuner(struct file *file, void *priv, | 1986 | static int saa7134_s_tuner(struct file *file, void *priv, |
1992 | struct v4l2_tuner *t) | 1987 | struct v4l2_tuner *t) |
1993 | { | 1988 | { |
1994 | struct saa7134_fh *fh = priv; | 1989 | struct saa7134_fh *fh = priv; |
1995 | struct saa7134_dev *dev = fh->dev; | 1990 | struct saa7134_dev *dev = fh->dev; |
1996 | int rx, mode, err; | 1991 | int rx, mode, err; |
1997 | 1992 | ||
1998 | err = v4l2_prio_check(&dev->prio, &fh->prio); | 1993 | err = v4l2_prio_check(&dev->prio, &fh->prio); |
1999 | if (0 != err) | 1994 | if (0 != err) |
2000 | return err; | 1995 | return err; |
2001 | 1996 | ||
2002 | mode = dev->thread.mode; | 1997 | mode = dev->thread.mode; |
2003 | if (UNSET == mode) { | 1998 | if (UNSET == mode) { |
2004 | rx = saa7134_tvaudio_getstereo(dev); | 1999 | rx = saa7134_tvaudio_getstereo(dev); |
2005 | mode = saa7134_tvaudio_rx2mode(t->rxsubchans); | 2000 | mode = saa7134_tvaudio_rx2mode(t->rxsubchans); |
2006 | } | 2001 | } |
2007 | if (mode != t->audmode) | 2002 | if (mode != t->audmode) |
2008 | dev->thread.mode = t->audmode; | 2003 | dev->thread.mode = t->audmode; |
2009 | 2004 | ||
2010 | return 0; | 2005 | return 0; |
2011 | } | 2006 | } |
2012 | 2007 | ||
2013 | static int saa7134_g_frequency(struct file *file, void *priv, | 2008 | static int saa7134_g_frequency(struct file *file, void *priv, |
2014 | struct v4l2_frequency *f) | 2009 | struct v4l2_frequency *f) |
2015 | { | 2010 | { |
2016 | struct saa7134_fh *fh = priv; | 2011 | struct saa7134_fh *fh = priv; |
2017 | struct saa7134_dev *dev = fh->dev; | 2012 | struct saa7134_dev *dev = fh->dev; |
2018 | 2013 | ||
2019 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 2014 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; |
2020 | f->frequency = dev->ctl_freq; | 2015 | f->frequency = dev->ctl_freq; |
2021 | 2016 | ||
2022 | return 0; | 2017 | return 0; |
2023 | } | 2018 | } |
2024 | 2019 | ||
2025 | static int saa7134_s_frequency(struct file *file, void *priv, | 2020 | static int saa7134_s_frequency(struct file *file, void *priv, |
2026 | struct v4l2_frequency *f) | 2021 | struct v4l2_frequency *f) |
2027 | { | 2022 | { |
2028 | struct saa7134_fh *fh = priv; | 2023 | struct saa7134_fh *fh = priv; |
2029 | struct saa7134_dev *dev = fh->dev; | 2024 | struct saa7134_dev *dev = fh->dev; |
2030 | int err; | 2025 | int err; |
2031 | 2026 | ||
2032 | err = v4l2_prio_check(&dev->prio, &fh->prio); | 2027 | err = v4l2_prio_check(&dev->prio, &fh->prio); |
2033 | if (0 != err) | 2028 | if (0 != err) |
2034 | return err; | 2029 | return err; |
2035 | 2030 | ||
2036 | if (0 != f->tuner) | 2031 | if (0 != f->tuner) |
2037 | return -EINVAL; | 2032 | return -EINVAL; |
2038 | if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) | 2033 | if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) |
2039 | return -EINVAL; | 2034 | return -EINVAL; |
2040 | if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) | 2035 | if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) |
2041 | return -EINVAL; | 2036 | return -EINVAL; |
2042 | mutex_lock(&dev->lock); | 2037 | mutex_lock(&dev->lock); |
2043 | dev->ctl_freq = f->frequency; | 2038 | dev->ctl_freq = f->frequency; |
2044 | 2039 | ||
2045 | saa_call_all(dev, tuner, s_frequency, f); | 2040 | saa_call_all(dev, tuner, s_frequency, f); |
2046 | 2041 | ||
2047 | saa7134_tvaudio_do_scan(dev); | 2042 | saa7134_tvaudio_do_scan(dev); |
2048 | mutex_unlock(&dev->lock); | 2043 | mutex_unlock(&dev->lock); |
2049 | return 0; | 2044 | return 0; |
2050 | } | 2045 | } |
2051 | 2046 | ||
2052 | static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) | 2047 | static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) |
2053 | { | 2048 | { |
2054 | strcpy(a->name, "audio"); | 2049 | strcpy(a->name, "audio"); |
2055 | return 0; | 2050 | return 0; |
2056 | } | 2051 | } |
2057 | 2052 | ||
2058 | static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) | 2053 | static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) |
2059 | { | 2054 | { |
2060 | return 0; | 2055 | return 0; |
2061 | } | 2056 | } |
2062 | 2057 | ||
2063 | static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) | 2058 | static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) |
2064 | { | 2059 | { |
2065 | struct saa7134_fh *fh = f; | 2060 | struct saa7134_fh *fh = f; |
2066 | struct saa7134_dev *dev = fh->dev; | 2061 | struct saa7134_dev *dev = fh->dev; |
2067 | 2062 | ||
2068 | *p = v4l2_prio_max(&dev->prio); | 2063 | *p = v4l2_prio_max(&dev->prio); |
2069 | return 0; | 2064 | return 0; |
2070 | } | 2065 | } |
2071 | 2066 | ||
2072 | static int saa7134_s_priority(struct file *file, void *f, | 2067 | static int saa7134_s_priority(struct file *file, void *f, |
2073 | enum v4l2_priority prio) | 2068 | enum v4l2_priority prio) |
2074 | { | 2069 | { |
2075 | struct saa7134_fh *fh = f; | 2070 | struct saa7134_fh *fh = f; |
2076 | struct saa7134_dev *dev = fh->dev; | 2071 | struct saa7134_dev *dev = fh->dev; |
2077 | 2072 | ||
2078 | return v4l2_prio_change(&dev->prio, &fh->prio, prio); | 2073 | return v4l2_prio_change(&dev->prio, &fh->prio, prio); |
2079 | } | 2074 | } |
2080 | 2075 | ||
2081 | static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, | 2076 | static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, |
2082 | struct v4l2_fmtdesc *f) | 2077 | struct v4l2_fmtdesc *f) |
2083 | { | 2078 | { |
2084 | if (f->index >= FORMATS) | 2079 | if (f->index >= FORMATS) |
2085 | return -EINVAL; | 2080 | return -EINVAL; |
2086 | 2081 | ||
2087 | strlcpy(f->description, formats[f->index].name, | 2082 | strlcpy(f->description, formats[f->index].name, |
2088 | sizeof(f->description)); | 2083 | sizeof(f->description)); |
2089 | 2084 | ||
2090 | f->pixelformat = formats[f->index].fourcc; | 2085 | f->pixelformat = formats[f->index].fourcc; |
2091 | 2086 | ||
2092 | return 0; | 2087 | return 0; |
2093 | } | 2088 | } |
2094 | 2089 | ||
2095 | static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, | 2090 | static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, |
2096 | struct v4l2_fmtdesc *f) | 2091 | struct v4l2_fmtdesc *f) |
2097 | { | 2092 | { |
2098 | if (saa7134_no_overlay > 0) { | 2093 | if (saa7134_no_overlay > 0) { |
2099 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); | 2094 | printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); |
2100 | return -EINVAL; | 2095 | return -EINVAL; |
2101 | } | 2096 | } |
2102 | 2097 | ||
2103 | if ((f->index >= FORMATS) || formats[f->index].planar) | 2098 | if ((f->index >= FORMATS) || formats[f->index].planar) |
2104 | return -EINVAL; | 2099 | return -EINVAL; |
2105 | 2100 | ||
2106 | strlcpy(f->description, formats[f->index].name, | 2101 | strlcpy(f->description, formats[f->index].name, |
2107 | sizeof(f->description)); | 2102 | sizeof(f->description)); |
2108 | 2103 | ||
2109 | f->pixelformat = formats[f->index].fourcc; | 2104 | f->pixelformat = formats[f->index].fourcc; |
2110 | 2105 | ||
2111 | return 0; | 2106 | return 0; |
2112 | } | 2107 | } |
2113 | 2108 | ||
2114 | static int saa7134_g_fbuf(struct file *file, void *f, | 2109 | static int saa7134_g_fbuf(struct file *file, void *f, |
2115 | struct v4l2_framebuffer *fb) | 2110 | struct v4l2_framebuffer *fb) |
2116 | { | 2111 | { |
2117 | struct saa7134_fh *fh = f; | 2112 | struct saa7134_fh *fh = f; |
2118 | struct saa7134_dev *dev = fh->dev; | 2113 | struct saa7134_dev *dev = fh->dev; |
2119 | 2114 | ||
2120 | *fb = dev->ovbuf; | 2115 | *fb = dev->ovbuf; |
2121 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | 2116 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; |
2122 | 2117 | ||
2123 | return 0; | 2118 | return 0; |
2124 | } | 2119 | } |
2125 | 2120 | ||
2126 | static int saa7134_s_fbuf(struct file *file, void *f, | 2121 | static int saa7134_s_fbuf(struct file *file, void *f, |
2127 | struct v4l2_framebuffer *fb) | 2122 | struct v4l2_framebuffer *fb) |
2128 | { | 2123 | { |
2129 | struct saa7134_fh *fh = f; | 2124 | struct saa7134_fh *fh = f; |
2130 | struct saa7134_dev *dev = fh->dev; | 2125 | struct saa7134_dev *dev = fh->dev; |
2131 | struct saa7134_format *fmt; | 2126 | struct saa7134_format *fmt; |
2132 | 2127 | ||
2133 | if (!capable(CAP_SYS_ADMIN) && | 2128 | if (!capable(CAP_SYS_ADMIN) && |
2134 | !capable(CAP_SYS_RAWIO)) | 2129 | !capable(CAP_SYS_RAWIO)) |
2135 | return -EPERM; | 2130 | return -EPERM; |
2136 | 2131 | ||
2137 | /* check args */ | 2132 | /* check args */ |
2138 | fmt = format_by_fourcc(fb->fmt.pixelformat); | 2133 | fmt = format_by_fourcc(fb->fmt.pixelformat); |
2139 | if (NULL == fmt) | 2134 | if (NULL == fmt) |
2140 | return -EINVAL; | 2135 | return -EINVAL; |
2141 | 2136 | ||
2142 | /* ok, accept it */ | 2137 | /* ok, accept it */ |
2143 | dev->ovbuf = *fb; | 2138 | dev->ovbuf = *fb; |
2144 | dev->ovfmt = fmt; | 2139 | dev->ovfmt = fmt; |
2145 | if (0 == dev->ovbuf.fmt.bytesperline) | 2140 | if (0 == dev->ovbuf.fmt.bytesperline) |
2146 | dev->ovbuf.fmt.bytesperline = | 2141 | dev->ovbuf.fmt.bytesperline = |
2147 | dev->ovbuf.fmt.width*fmt->depth/8; | 2142 | dev->ovbuf.fmt.width*fmt->depth/8; |
2148 | return 0; | 2143 | return 0; |
2149 | } | 2144 | } |
2150 | 2145 | ||
2151 | static int saa7134_overlay(struct file *file, void *f, unsigned int on) | 2146 | static int saa7134_overlay(struct file *file, void *f, unsigned int on) |
2152 | { | 2147 | { |
2153 | struct saa7134_fh *fh = f; | 2148 | struct saa7134_fh *fh = f; |
2154 | struct saa7134_dev *dev = fh->dev; | 2149 | struct saa7134_dev *dev = fh->dev; |
2155 | unsigned long flags; | 2150 | unsigned long flags; |
2156 | 2151 | ||
2157 | if (on) { | 2152 | if (on) { |
2158 | if (saa7134_no_overlay > 0) { | 2153 | if (saa7134_no_overlay > 0) { |
2159 | dprintk("no_overlay\n"); | 2154 | dprintk("no_overlay\n"); |
2160 | return -EINVAL; | 2155 | return -EINVAL; |
2161 | } | 2156 | } |
2162 | 2157 | ||
2163 | if (!res_get(dev, fh, RESOURCE_OVERLAY)) | 2158 | if (!res_get(dev, fh, RESOURCE_OVERLAY)) |
2164 | return -EBUSY; | 2159 | return -EBUSY; |
2165 | spin_lock_irqsave(&dev->slock, flags); | 2160 | spin_lock_irqsave(&dev->slock, flags); |
2166 | start_preview(dev, fh); | 2161 | start_preview(dev, fh); |
2167 | spin_unlock_irqrestore(&dev->slock, flags); | 2162 | spin_unlock_irqrestore(&dev->slock, flags); |
2168 | } | 2163 | } |
2169 | if (!on) { | 2164 | if (!on) { |
2170 | if (!res_check(fh, RESOURCE_OVERLAY)) | 2165 | if (!res_check(fh, RESOURCE_OVERLAY)) |
2171 | return -EINVAL; | 2166 | return -EINVAL; |
2172 | spin_lock_irqsave(&dev->slock, flags); | 2167 | spin_lock_irqsave(&dev->slock, flags); |
2173 | stop_preview(dev, fh); | 2168 | stop_preview(dev, fh); |
2174 | spin_unlock_irqrestore(&dev->slock, flags); | 2169 | spin_unlock_irqrestore(&dev->slock, flags); |
2175 | res_free(dev, fh, RESOURCE_OVERLAY); | 2170 | res_free(dev, fh, RESOURCE_OVERLAY); |
2176 | } | 2171 | } |
2177 | return 0; | 2172 | return 0; |
2178 | } | 2173 | } |
2179 | 2174 | ||
2180 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 2175 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
2181 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) | 2176 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) |
2182 | { | 2177 | { |
2183 | struct saa7134_fh *fh = file->private_data; | 2178 | struct saa7134_fh *fh = file->private_data; |
2184 | return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); | 2179 | return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); |
2185 | } | 2180 | } |
2186 | #endif | 2181 | #endif |
2187 | 2182 | ||
2188 | static int saa7134_reqbufs(struct file *file, void *priv, | 2183 | static int saa7134_reqbufs(struct file *file, void *priv, |
2189 | struct v4l2_requestbuffers *p) | 2184 | struct v4l2_requestbuffers *p) |
2190 | { | 2185 | { |
2191 | struct saa7134_fh *fh = priv; | 2186 | struct saa7134_fh *fh = priv; |
2192 | return videobuf_reqbufs(saa7134_queue(fh), p); | 2187 | return videobuf_reqbufs(saa7134_queue(fh), p); |
2193 | } | 2188 | } |
2194 | 2189 | ||
2195 | static int saa7134_querybuf(struct file *file, void *priv, | 2190 | static int saa7134_querybuf(struct file *file, void *priv, |
2196 | struct v4l2_buffer *b) | 2191 | struct v4l2_buffer *b) |
2197 | { | 2192 | { |
2198 | struct saa7134_fh *fh = priv; | 2193 | struct saa7134_fh *fh = priv; |
2199 | return videobuf_querybuf(saa7134_queue(fh), b); | 2194 | return videobuf_querybuf(saa7134_queue(fh), b); |
2200 | } | 2195 | } |
2201 | 2196 | ||
2202 | static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 2197 | static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
2203 | { | 2198 | { |
2204 | struct saa7134_fh *fh = priv; | 2199 | struct saa7134_fh *fh = priv; |
2205 | return videobuf_qbuf(saa7134_queue(fh), b); | 2200 | return videobuf_qbuf(saa7134_queue(fh), b); |
2206 | } | 2201 | } |
2207 | 2202 | ||
2208 | static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 2203 | static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
2209 | { | 2204 | { |
2210 | struct saa7134_fh *fh = priv; | 2205 | struct saa7134_fh *fh = priv; |
2211 | return videobuf_dqbuf(saa7134_queue(fh), b, | 2206 | return videobuf_dqbuf(saa7134_queue(fh), b, |
2212 | file->f_flags & O_NONBLOCK); | 2207 | file->f_flags & O_NONBLOCK); |
2213 | } | 2208 | } |
2214 | 2209 | ||
2215 | static int saa7134_streamon(struct file *file, void *priv, | 2210 | static int saa7134_streamon(struct file *file, void *priv, |
2216 | enum v4l2_buf_type type) | 2211 | enum v4l2_buf_type type) |
2217 | { | 2212 | { |
2218 | struct saa7134_fh *fh = priv; | 2213 | struct saa7134_fh *fh = priv; |
2219 | struct saa7134_dev *dev = fh->dev; | 2214 | struct saa7134_dev *dev = fh->dev; |
2220 | int res = saa7134_resource(fh); | 2215 | int res = saa7134_resource(fh); |
2221 | 2216 | ||
2222 | if (!res_get(dev, fh, res)) | 2217 | if (!res_get(dev, fh, res)) |
2223 | return -EBUSY; | 2218 | return -EBUSY; |
2224 | 2219 | ||
2225 | return videobuf_streamon(saa7134_queue(fh)); | 2220 | return videobuf_streamon(saa7134_queue(fh)); |
2226 | } | 2221 | } |
2227 | 2222 | ||
2228 | static int saa7134_streamoff(struct file *file, void *priv, | 2223 | static int saa7134_streamoff(struct file *file, void *priv, |
2229 | enum v4l2_buf_type type) | 2224 | enum v4l2_buf_type type) |
2230 | { | 2225 | { |
2231 | int err; | 2226 | int err; |
2232 | struct saa7134_fh *fh = priv; | 2227 | struct saa7134_fh *fh = priv; |
2233 | struct saa7134_dev *dev = fh->dev; | 2228 | struct saa7134_dev *dev = fh->dev; |
2234 | int res = saa7134_resource(fh); | 2229 | int res = saa7134_resource(fh); |
2235 | 2230 | ||
2236 | err = videobuf_streamoff(saa7134_queue(fh)); | 2231 | err = videobuf_streamoff(saa7134_queue(fh)); |
2237 | if (err < 0) | 2232 | if (err < 0) |
2238 | return err; | 2233 | return err; |
2239 | res_free(dev, fh, res); | 2234 | res_free(dev, fh, res); |
2240 | return 0; | 2235 | return 0; |
2241 | } | 2236 | } |
2242 | 2237 | ||
2243 | static int saa7134_g_parm(struct file *file, void *fh, | 2238 | static int saa7134_g_parm(struct file *file, void *fh, |
2244 | struct v4l2_streamparm *parm) | 2239 | struct v4l2_streamparm *parm) |
2245 | { | 2240 | { |
2246 | return 0; | 2241 | return 0; |
2247 | } | 2242 | } |
2248 | 2243 | ||
2249 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 2244 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
2250 | static int vidioc_g_register (struct file *file, void *priv, | 2245 | static int vidioc_g_register (struct file *file, void *priv, |
2251 | struct v4l2_dbg_register *reg) | 2246 | struct v4l2_dbg_register *reg) |
2252 | { | 2247 | { |
2253 | struct saa7134_fh *fh = priv; | 2248 | struct saa7134_fh *fh = priv; |
2254 | struct saa7134_dev *dev = fh->dev; | 2249 | struct saa7134_dev *dev = fh->dev; |
2255 | 2250 | ||
2256 | if (!v4l2_chip_match_host(®->match)) | 2251 | if (!v4l2_chip_match_host(®->match)) |
2257 | return -EINVAL; | 2252 | return -EINVAL; |
2258 | reg->val = saa_readb(reg->reg); | 2253 | reg->val = saa_readb(reg->reg); |
2259 | reg->size = 1; | 2254 | reg->size = 1; |
2260 | return 0; | 2255 | return 0; |
2261 | } | 2256 | } |
2262 | 2257 | ||
2263 | static int vidioc_s_register (struct file *file, void *priv, | 2258 | static int vidioc_s_register (struct file *file, void *priv, |
2264 | struct v4l2_dbg_register *reg) | 2259 | struct v4l2_dbg_register *reg) |
2265 | { | 2260 | { |
2266 | struct saa7134_fh *fh = priv; | 2261 | struct saa7134_fh *fh = priv; |
2267 | struct saa7134_dev *dev = fh->dev; | 2262 | struct saa7134_dev *dev = fh->dev; |
2268 | 2263 | ||
2269 | if (!v4l2_chip_match_host(®->match)) | 2264 | if (!v4l2_chip_match_host(®->match)) |
2270 | return -EINVAL; | 2265 | return -EINVAL; |
2271 | saa_writeb(reg->reg&0xffffff, reg->val); | 2266 | saa_writeb(reg->reg&0xffffff, reg->val); |
2272 | return 0; | 2267 | return 0; |
2273 | } | 2268 | } |
2274 | #endif | 2269 | #endif |
2275 | 2270 | ||
2276 | static int radio_querycap(struct file *file, void *priv, | 2271 | static int radio_querycap(struct file *file, void *priv, |
2277 | struct v4l2_capability *cap) | 2272 | struct v4l2_capability *cap) |
2278 | { | 2273 | { |
2279 | struct saa7134_fh *fh = file->private_data; | 2274 | struct saa7134_fh *fh = file->private_data; |
2280 | struct saa7134_dev *dev = fh->dev; | 2275 | struct saa7134_dev *dev = fh->dev; |
2281 | 2276 | ||
2282 | strcpy(cap->driver, "saa7134"); | 2277 | strcpy(cap->driver, "saa7134"); |
2283 | strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); | 2278 | strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); |
2284 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | 2279 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); |
2285 | cap->version = SAA7134_VERSION_CODE; | 2280 | cap->version = SAA7134_VERSION_CODE; |
2286 | cap->capabilities = V4L2_CAP_TUNER; | 2281 | cap->capabilities = V4L2_CAP_TUNER; |
2287 | return 0; | 2282 | return 0; |
2288 | } | 2283 | } |
2289 | 2284 | ||
2290 | static int radio_g_tuner(struct file *file, void *priv, | 2285 | static int radio_g_tuner(struct file *file, void *priv, |
2291 | struct v4l2_tuner *t) | 2286 | struct v4l2_tuner *t) |
2292 | { | 2287 | { |
2293 | struct saa7134_fh *fh = file->private_data; | 2288 | struct saa7134_fh *fh = file->private_data; |
2294 | struct saa7134_dev *dev = fh->dev; | 2289 | struct saa7134_dev *dev = fh->dev; |
2295 | 2290 | ||
2296 | if (0 != t->index) | 2291 | if (0 != t->index) |
2297 | return -EINVAL; | 2292 | return -EINVAL; |
2298 | 2293 | ||
2299 | memset(t, 0, sizeof(*t)); | 2294 | memset(t, 0, sizeof(*t)); |
2300 | strcpy(t->name, "Radio"); | 2295 | strcpy(t->name, "Radio"); |
2301 | t->type = V4L2_TUNER_RADIO; | 2296 | t->type = V4L2_TUNER_RADIO; |
2302 | 2297 | ||
2303 | saa_call_all(dev, tuner, g_tuner, t); | 2298 | saa_call_all(dev, tuner, g_tuner, t); |
2304 | if (dev->input->amux == TV) { | 2299 | if (dev->input->amux == TV) { |
2305 | t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); | 2300 | t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); |
2306 | t->rxsubchans = (saa_readb(0x529) & 0x08) ? | 2301 | t->rxsubchans = (saa_readb(0x529) & 0x08) ? |
2307 | V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; | 2302 | V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; |
2308 | } | 2303 | } |
2309 | return 0; | 2304 | return 0; |
2310 | } | 2305 | } |
2311 | static int radio_s_tuner(struct file *file, void *priv, | 2306 | static int radio_s_tuner(struct file *file, void *priv, |
2312 | struct v4l2_tuner *t) | 2307 | struct v4l2_tuner *t) |
2313 | { | 2308 | { |
2314 | struct saa7134_fh *fh = file->private_data; | 2309 | struct saa7134_fh *fh = file->private_data; |
2315 | struct saa7134_dev *dev = fh->dev; | 2310 | struct saa7134_dev *dev = fh->dev; |
2316 | 2311 | ||
2317 | if (0 != t->index) | 2312 | if (0 != t->index) |
2318 | return -EINVAL; | 2313 | return -EINVAL; |
2319 | 2314 | ||
2320 | saa_call_all(dev, tuner, s_tuner, t); | 2315 | saa_call_all(dev, tuner, s_tuner, t); |
2321 | return 0; | 2316 | return 0; |
2322 | } | 2317 | } |
2323 | 2318 | ||
2324 | static int radio_enum_input(struct file *file, void *priv, | 2319 | static int radio_enum_input(struct file *file, void *priv, |
2325 | struct v4l2_input *i) | 2320 | struct v4l2_input *i) |
2326 | { | 2321 | { |
2327 | if (i->index != 0) | 2322 | if (i->index != 0) |
2328 | return -EINVAL; | 2323 | return -EINVAL; |
2329 | 2324 | ||
2330 | strcpy(i->name, "Radio"); | 2325 | strcpy(i->name, "Radio"); |
2331 | i->type = V4L2_INPUT_TYPE_TUNER; | 2326 | i->type = V4L2_INPUT_TYPE_TUNER; |
2332 | 2327 | ||
2333 | return 0; | 2328 | return 0; |
2334 | } | 2329 | } |
2335 | 2330 | ||
2336 | static int radio_g_input(struct file *filp, void *priv, unsigned int *i) | 2331 | static int radio_g_input(struct file *filp, void *priv, unsigned int *i) |
2337 | { | 2332 | { |
2338 | *i = 0; | 2333 | *i = 0; |
2339 | return 0; | 2334 | return 0; |
2340 | } | 2335 | } |
2341 | 2336 | ||
2342 | static int radio_g_audio(struct file *file, void *priv, | 2337 | static int radio_g_audio(struct file *file, void *priv, |
2343 | struct v4l2_audio *a) | 2338 | struct v4l2_audio *a) |
2344 | { | 2339 | { |
2345 | memset(a, 0, sizeof(*a)); | 2340 | memset(a, 0, sizeof(*a)); |
2346 | strcpy(a->name, "Radio"); | 2341 | strcpy(a->name, "Radio"); |
2347 | return 0; | 2342 | return 0; |
2348 | } | 2343 | } |
2349 | 2344 | ||
2350 | static int radio_s_audio(struct file *file, void *priv, | 2345 | static int radio_s_audio(struct file *file, void *priv, |
2351 | struct v4l2_audio *a) | 2346 | struct v4l2_audio *a) |
2352 | { | 2347 | { |
2353 | return 0; | 2348 | return 0; |
2354 | } | 2349 | } |
2355 | 2350 | ||
2356 | static int radio_s_input(struct file *filp, void *priv, unsigned int i) | 2351 | static int radio_s_input(struct file *filp, void *priv, unsigned int i) |
2357 | { | 2352 | { |
2358 | return 0; | 2353 | return 0; |
2359 | } | 2354 | } |
2360 | 2355 | ||
2361 | static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) | 2356 | static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) |
2362 | { | 2357 | { |
2363 | return 0; | 2358 | return 0; |
2364 | } | 2359 | } |
2365 | 2360 | ||
2366 | static int radio_queryctrl(struct file *file, void *priv, | 2361 | static int radio_queryctrl(struct file *file, void *priv, |
2367 | struct v4l2_queryctrl *c) | 2362 | struct v4l2_queryctrl *c) |
2368 | { | 2363 | { |
2369 | const struct v4l2_queryctrl *ctrl; | 2364 | const struct v4l2_queryctrl *ctrl; |
2370 | 2365 | ||
2371 | if (c->id < V4L2_CID_BASE || | 2366 | if (c->id < V4L2_CID_BASE || |
2372 | c->id >= V4L2_CID_LASTP1) | 2367 | c->id >= V4L2_CID_LASTP1) |
2373 | return -EINVAL; | 2368 | return -EINVAL; |
2374 | if (c->id == V4L2_CID_AUDIO_MUTE) { | 2369 | if (c->id == V4L2_CID_AUDIO_MUTE) { |
2375 | ctrl = ctrl_by_id(c->id); | 2370 | ctrl = ctrl_by_id(c->id); |
2376 | *c = *ctrl; | 2371 | *c = *ctrl; |
2377 | } else | 2372 | } else |
2378 | *c = no_ctrl; | 2373 | *c = no_ctrl; |
2379 | return 0; | 2374 | return 0; |
2380 | } | 2375 | } |
2381 | 2376 | ||
2382 | static const struct v4l2_file_operations video_fops = | 2377 | static const struct v4l2_file_operations video_fops = |
2383 | { | 2378 | { |
2384 | .owner = THIS_MODULE, | 2379 | .owner = THIS_MODULE, |
2385 | .open = video_open, | 2380 | .open = video_open, |
2386 | .release = video_release, | 2381 | .release = video_release, |
2387 | .read = video_read, | 2382 | .read = video_read, |
2388 | .poll = video_poll, | 2383 | .poll = video_poll, |
2389 | .mmap = video_mmap, | 2384 | .mmap = video_mmap, |
2390 | .ioctl = video_ioctl2, | 2385 | .ioctl = video_ioctl2, |
2391 | }; | 2386 | }; |
2392 | 2387 | ||
2393 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | 2388 | static const struct v4l2_ioctl_ops video_ioctl_ops = { |
2394 | .vidioc_querycap = saa7134_querycap, | 2389 | .vidioc_querycap = saa7134_querycap, |
2395 | .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, | 2390 | .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, |
2396 | .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, | 2391 | .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, |
2397 | .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap, | 2392 | .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap, |
2398 | .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap, | 2393 | .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap, |
2399 | .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay, | 2394 | .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay, |
2400 | .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay, | 2395 | .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay, |
2401 | .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay, | 2396 | .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay, |
2402 | .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay, | 2397 | .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay, |
2403 | .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, | 2398 | .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
2404 | .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, | 2399 | .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
2405 | .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, | 2400 | .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, |
2406 | .vidioc_g_audio = saa7134_g_audio, | 2401 | .vidioc_g_audio = saa7134_g_audio, |
2407 | .vidioc_s_audio = saa7134_s_audio, | 2402 | .vidioc_s_audio = saa7134_s_audio, |
2408 | .vidioc_cropcap = saa7134_cropcap, | 2403 | .vidioc_cropcap = saa7134_cropcap, |
2409 | .vidioc_reqbufs = saa7134_reqbufs, | 2404 | .vidioc_reqbufs = saa7134_reqbufs, |
2410 | .vidioc_querybuf = saa7134_querybuf, | 2405 | .vidioc_querybuf = saa7134_querybuf, |
2411 | .vidioc_qbuf = saa7134_qbuf, | 2406 | .vidioc_qbuf = saa7134_qbuf, |
2412 | .vidioc_dqbuf = saa7134_dqbuf, | 2407 | .vidioc_dqbuf = saa7134_dqbuf, |
2413 | .vidioc_s_std = saa7134_s_std, | 2408 | .vidioc_s_std = saa7134_s_std, |
2414 | .vidioc_g_std = saa7134_g_std, | 2409 | .vidioc_g_std = saa7134_g_std, |
2415 | .vidioc_enum_input = saa7134_enum_input, | 2410 | .vidioc_enum_input = saa7134_enum_input, |
2416 | .vidioc_g_input = saa7134_g_input, | 2411 | .vidioc_g_input = saa7134_g_input, |
2417 | .vidioc_s_input = saa7134_s_input, | 2412 | .vidioc_s_input = saa7134_s_input, |
2418 | .vidioc_queryctrl = saa7134_queryctrl, | 2413 | .vidioc_queryctrl = saa7134_queryctrl, |
2419 | .vidioc_g_ctrl = saa7134_g_ctrl, | 2414 | .vidioc_g_ctrl = saa7134_g_ctrl, |
2420 | .vidioc_s_ctrl = saa7134_s_ctrl, | 2415 | .vidioc_s_ctrl = saa7134_s_ctrl, |
2421 | .vidioc_streamon = saa7134_streamon, | 2416 | .vidioc_streamon = saa7134_streamon, |
2422 | .vidioc_streamoff = saa7134_streamoff, | 2417 | .vidioc_streamoff = saa7134_streamoff, |
2423 | .vidioc_g_tuner = saa7134_g_tuner, | 2418 | .vidioc_g_tuner = saa7134_g_tuner, |
2424 | .vidioc_s_tuner = saa7134_s_tuner, | 2419 | .vidioc_s_tuner = saa7134_s_tuner, |
2425 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 2420 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
2426 | .vidiocgmbuf = vidiocgmbuf, | 2421 | .vidiocgmbuf = vidiocgmbuf, |
2427 | #endif | 2422 | #endif |
2428 | .vidioc_g_crop = saa7134_g_crop, | 2423 | .vidioc_g_crop = saa7134_g_crop, |
2429 | .vidioc_s_crop = saa7134_s_crop, | 2424 | .vidioc_s_crop = saa7134_s_crop, |
2430 | .vidioc_g_fbuf = saa7134_g_fbuf, | 2425 | .vidioc_g_fbuf = saa7134_g_fbuf, |
2431 | .vidioc_s_fbuf = saa7134_s_fbuf, | 2426 | .vidioc_s_fbuf = saa7134_s_fbuf, |
2432 | .vidioc_overlay = saa7134_overlay, | 2427 | .vidioc_overlay = saa7134_overlay, |
2433 | .vidioc_g_priority = saa7134_g_priority, | 2428 | .vidioc_g_priority = saa7134_g_priority, |
2434 | .vidioc_s_priority = saa7134_s_priority, | 2429 | .vidioc_s_priority = saa7134_s_priority, |
2435 | .vidioc_g_parm = saa7134_g_parm, | 2430 | .vidioc_g_parm = saa7134_g_parm, |
2436 | .vidioc_g_frequency = saa7134_g_frequency, | 2431 | .vidioc_g_frequency = saa7134_g_frequency, |
2437 | .vidioc_s_frequency = saa7134_s_frequency, | 2432 | .vidioc_s_frequency = saa7134_s_frequency, |
2438 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 2433 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
2439 | .vidioc_g_register = vidioc_g_register, | 2434 | .vidioc_g_register = vidioc_g_register, |
2440 | .vidioc_s_register = vidioc_s_register, | 2435 | .vidioc_s_register = vidioc_s_register, |
2441 | #endif | 2436 | #endif |
2442 | }; | 2437 | }; |
2443 | 2438 | ||
2444 | static const struct v4l2_file_operations radio_fops = { | 2439 | static const struct v4l2_file_operations radio_fops = { |
2445 | .owner = THIS_MODULE, | 2440 | .owner = THIS_MODULE, |
2446 | .open = video_open, | 2441 | .open = video_open, |
2447 | .release = video_release, | 2442 | .release = video_release, |
2448 | .ioctl = video_ioctl2, | 2443 | .ioctl = video_ioctl2, |
2449 | }; | 2444 | }; |
2450 | 2445 | ||
2451 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { | 2446 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { |
2452 | .vidioc_querycap = radio_querycap, | 2447 | .vidioc_querycap = radio_querycap, |
2453 | .vidioc_g_tuner = radio_g_tuner, | 2448 | .vidioc_g_tuner = radio_g_tuner, |
2454 | .vidioc_enum_input = radio_enum_input, | 2449 | .vidioc_enum_input = radio_enum_input, |
2455 | .vidioc_g_audio = radio_g_audio, | 2450 | .vidioc_g_audio = radio_g_audio, |
2456 | .vidioc_s_tuner = radio_s_tuner, | 2451 | .vidioc_s_tuner = radio_s_tuner, |
2457 | .vidioc_s_audio = radio_s_audio, | 2452 | .vidioc_s_audio = radio_s_audio, |
2458 | .vidioc_s_input = radio_s_input, | 2453 | .vidioc_s_input = radio_s_input, |
2459 | .vidioc_s_std = radio_s_std, | 2454 | .vidioc_s_std = radio_s_std, |
2460 | .vidioc_queryctrl = radio_queryctrl, | 2455 | .vidioc_queryctrl = radio_queryctrl, |
2461 | .vidioc_g_input = radio_g_input, | 2456 | .vidioc_g_input = radio_g_input, |
2462 | .vidioc_g_ctrl = saa7134_g_ctrl, | 2457 | .vidioc_g_ctrl = saa7134_g_ctrl, |
2463 | .vidioc_s_ctrl = saa7134_s_ctrl, | 2458 | .vidioc_s_ctrl = saa7134_s_ctrl, |
2464 | .vidioc_g_frequency = saa7134_g_frequency, | 2459 | .vidioc_g_frequency = saa7134_g_frequency, |
2465 | .vidioc_s_frequency = saa7134_s_frequency, | 2460 | .vidioc_s_frequency = saa7134_s_frequency, |
2466 | }; | 2461 | }; |
2467 | 2462 | ||
2468 | /* ----------------------------------------------------------- */ | 2463 | /* ----------------------------------------------------------- */ |
2469 | /* exported stuff */ | 2464 | /* exported stuff */ |
2470 | 2465 | ||
2471 | struct video_device saa7134_video_template = { | 2466 | struct video_device saa7134_video_template = { |
2472 | .name = "saa7134-video", | 2467 | .name = "saa7134-video", |
2473 | .fops = &video_fops, | 2468 | .fops = &video_fops, |
2474 | .ioctl_ops = &video_ioctl_ops, | 2469 | .ioctl_ops = &video_ioctl_ops, |
2475 | .minor = -1, | 2470 | .minor = -1, |
2476 | .tvnorms = SAA7134_NORMS, | 2471 | .tvnorms = SAA7134_NORMS, |
2477 | .current_norm = V4L2_STD_PAL, | 2472 | .current_norm = V4L2_STD_PAL, |
2478 | }; | 2473 | }; |
2479 | 2474 | ||
2480 | struct video_device saa7134_radio_template = { | 2475 | struct video_device saa7134_radio_template = { |
2481 | .name = "saa7134-radio", | 2476 | .name = "saa7134-radio", |
2482 | .fops = &radio_fops, | 2477 | .fops = &radio_fops, |
2483 | .ioctl_ops = &radio_ioctl_ops, | 2478 | .ioctl_ops = &radio_ioctl_ops, |
2484 | .minor = -1, | 2479 | .minor = -1, |
2485 | }; | 2480 | }; |
2486 | 2481 | ||
2487 | int saa7134_video_init1(struct saa7134_dev *dev) | 2482 | int saa7134_video_init1(struct saa7134_dev *dev) |
2488 | { | 2483 | { |
2489 | /* sanitycheck insmod options */ | 2484 | /* sanitycheck insmod options */ |
2490 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) | 2485 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) |
2491 | gbuffers = 2; | 2486 | gbuffers = 2; |
2492 | if (gbufsize < 0 || gbufsize > gbufsize_max) | 2487 | if (gbufsize < 0 || gbufsize > gbufsize_max) |
2493 | gbufsize = gbufsize_max; | 2488 | gbufsize = gbufsize_max; |
2494 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; | 2489 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; |
2495 | 2490 | ||
2496 | /* put some sensible defaults into the data structures ... */ | 2491 | /* put some sensible defaults into the data structures ... */ |
2497 | dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; | 2492 | dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; |
2498 | dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; | 2493 | dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; |
2499 | dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; | 2494 | dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; |
2500 | dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; | 2495 | dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; |
2501 | dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; | 2496 | dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; |
2502 | dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; | 2497 | dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; |
2503 | dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; | 2498 | dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; |
2504 | dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; | 2499 | dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; |
2505 | 2500 | ||
2506 | if (dev->tda9887_conf && dev->ctl_automute) | 2501 | if (dev->tda9887_conf && dev->ctl_automute) |
2507 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | 2502 | dev->tda9887_conf |= TDA9887_AUTOMUTE; |
2508 | dev->automute = 0; | 2503 | dev->automute = 0; |
2509 | 2504 | ||
2510 | INIT_LIST_HEAD(&dev->video_q.queue); | 2505 | INIT_LIST_HEAD(&dev->video_q.queue); |
2511 | init_timer(&dev->video_q.timeout); | 2506 | init_timer(&dev->video_q.timeout); |
2512 | dev->video_q.timeout.function = saa7134_buffer_timeout; | 2507 | dev->video_q.timeout.function = saa7134_buffer_timeout; |
2513 | dev->video_q.timeout.data = (unsigned long)(&dev->video_q); | 2508 | dev->video_q.timeout.data = (unsigned long)(&dev->video_q); |
2514 | dev->video_q.dev = dev; | 2509 | dev->video_q.dev = dev; |
2515 | 2510 | ||
2516 | if (saa7134_boards[dev->board].video_out) | 2511 | if (saa7134_boards[dev->board].video_out) |
2517 | saa7134_videoport_init(dev); | 2512 | saa7134_videoport_init(dev); |
2518 | 2513 | ||
2519 | return 0; | 2514 | return 0; |
2520 | } | 2515 | } |
2521 | 2516 | ||
2522 | int saa7134_videoport_init(struct saa7134_dev *dev) | 2517 | int saa7134_videoport_init(struct saa7134_dev *dev) |
2523 | { | 2518 | { |
2524 | /* enable video output */ | 2519 | /* enable video output */ |
2525 | int vo = saa7134_boards[dev->board].video_out; | 2520 | int vo = saa7134_boards[dev->board].video_out; |
2526 | int video_reg; | 2521 | int video_reg; |
2527 | unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; | 2522 | unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; |
2528 | 2523 | ||
2529 | /* Configure videoport */ | 2524 | /* Configure videoport */ |
2530 | saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); | 2525 | saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); |
2531 | video_reg = video_out[vo][1]; | 2526 | video_reg = video_out[vo][1]; |
2532 | if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) | 2527 | if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) |
2533 | video_reg &= ~VP_T_CODE_P_INVERTED; | 2528 | video_reg &= ~VP_T_CODE_P_INVERTED; |
2534 | saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); | 2529 | saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); |
2535 | saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); | 2530 | saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); |
2536 | saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); | 2531 | saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); |
2537 | video_reg = video_out[vo][5]; | 2532 | video_reg = video_out[vo][5]; |
2538 | if (vid_port_opts & SET_CLOCK_NOT_DELAYED) | 2533 | if (vid_port_opts & SET_CLOCK_NOT_DELAYED) |
2539 | video_reg &= ~VP_CLK_CTRL2_DELAYED; | 2534 | video_reg &= ~VP_CLK_CTRL2_DELAYED; |
2540 | if (vid_port_opts & SET_CLOCK_INVERTED) | 2535 | if (vid_port_opts & SET_CLOCK_INVERTED) |
2541 | video_reg |= VP_CLK_CTRL1_INVERTED; | 2536 | video_reg |= VP_CLK_CTRL1_INVERTED; |
2542 | saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); | 2537 | saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); |
2543 | video_reg = video_out[vo][6]; | 2538 | video_reg = video_out[vo][6]; |
2544 | if (vid_port_opts & SET_VSYNC_OFF) { | 2539 | if (vid_port_opts & SET_VSYNC_OFF) { |
2545 | video_reg &= ~VP_VS_TYPE_MASK; | 2540 | video_reg &= ~VP_VS_TYPE_MASK; |
2546 | video_reg |= VP_VS_TYPE_OFF; | 2541 | video_reg |= VP_VS_TYPE_OFF; |
2547 | } | 2542 | } |
2548 | saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); | 2543 | saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); |
2549 | saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); | 2544 | saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); |
2550 | saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); | 2545 | saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); |
2551 | 2546 | ||
2552 | /* Start videoport */ | 2547 | /* Start videoport */ |
2553 | saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); | 2548 | saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); |
2554 | 2549 | ||
2555 | return 0; | 2550 | return 0; |
2556 | } | 2551 | } |
2557 | 2552 | ||
2558 | int saa7134_video_init2(struct saa7134_dev *dev) | 2553 | int saa7134_video_init2(struct saa7134_dev *dev) |
2559 | { | 2554 | { |
2560 | /* init video hw */ | 2555 | /* init video hw */ |
2561 | set_tvnorm(dev,&tvnorms[0]); | 2556 | set_tvnorm(dev,&tvnorms[0]); |
2562 | video_mux(dev,0); | 2557 | video_mux(dev,0); |
2563 | saa7134_tvaudio_setmute(dev); | 2558 | saa7134_tvaudio_setmute(dev); |
2564 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | 2559 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); |
2565 | return 0; | 2560 | return 0; |
2566 | } | 2561 | } |
2567 | 2562 | ||
2568 | void saa7134_irq_video_signalchange(struct saa7134_dev *dev) | 2563 | void saa7134_irq_video_signalchange(struct saa7134_dev *dev) |
2569 | { | 2564 | { |
2570 | static const char *st[] = { | 2565 | static const char *st[] = { |
2571 | "(no signal)", "NTSC", "PAL", "SECAM" }; | 2566 | "(no signal)", "NTSC", "PAL", "SECAM" }; |
2572 | u32 st1,st2; | 2567 | u32 st1,st2; |
2573 | 2568 | ||
2574 | st1 = saa_readb(SAA7134_STATUS_VIDEO1); | 2569 | st1 = saa_readb(SAA7134_STATUS_VIDEO1); |
2575 | st2 = saa_readb(SAA7134_STATUS_VIDEO2); | 2570 | st2 = saa_readb(SAA7134_STATUS_VIDEO2); |
2576 | dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", | 2571 | dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", |
2577 | (st1 & 0x40) ? "not locked" : "locked", | 2572 | (st1 & 0x40) ? "not locked" : "locked", |
2578 | (st2 & 0x40) ? "no" : "yes", | 2573 | (st2 & 0x40) ? "no" : "yes", |
2579 | st[st1 & 0x03]); | 2574 | st[st1 & 0x03]); |
2580 | dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); | 2575 | dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); |
2581 | 2576 | ||
2582 | if (dev->nosignal) { | 2577 | if (dev->nosignal) { |
2583 | /* no video signal -> mute audio */ | 2578 | /* no video signal -> mute audio */ |
2584 | if (dev->ctl_automute) | 2579 | if (dev->ctl_automute) |
2585 | dev->automute = 1; | 2580 | dev->automute = 1; |
2586 | saa7134_tvaudio_setmute(dev); | 2581 | saa7134_tvaudio_setmute(dev); |
2587 | } else { | 2582 | } else { |
2588 | /* wake up tvaudio audio carrier scan thread */ | 2583 | /* wake up tvaudio audio carrier scan thread */ |
2589 | saa7134_tvaudio_do_scan(dev); | 2584 | saa7134_tvaudio_do_scan(dev); |
2590 | } | 2585 | } |
2591 | 2586 | ||
2592 | if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) | 2587 | if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) |
2593 | saa_clearb(SAA7134_SYNC_CTRL, 0x20); | 2588 | saa_clearb(SAA7134_SYNC_CTRL, 0x20); |
2594 | else | 2589 | else |
2595 | saa_setb(SAA7134_SYNC_CTRL, 0x20); | 2590 | saa_setb(SAA7134_SYNC_CTRL, 0x20); |
2596 | 2591 | ||
2597 | if (dev->mops && dev->mops->signal_change) | 2592 | if (dev->mops && dev->mops->signal_change) |
2598 | dev->mops->signal_change(dev); | 2593 | dev->mops->signal_change(dev); |
2599 | } | 2594 | } |
2600 | 2595 | ||
2601 | 2596 | ||
2602 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) | 2597 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) |
2603 | { | 2598 | { |
2604 | enum v4l2_field field; | 2599 | enum v4l2_field field; |
2605 | 2600 | ||
2606 | spin_lock(&dev->slock); | 2601 | spin_lock(&dev->slock); |
2607 | if (dev->video_q.curr) { | 2602 | if (dev->video_q.curr) { |
2608 | dev->video_fieldcount++; | 2603 | dev->video_fieldcount++; |
2609 | field = dev->video_q.curr->vb.field; | 2604 | field = dev->video_q.curr->vb.field; |
2610 | if (V4L2_FIELD_HAS_BOTH(field)) { | 2605 | if (V4L2_FIELD_HAS_BOTH(field)) { |
2611 | /* make sure we have seen both fields */ | 2606 | /* make sure we have seen both fields */ |
2612 | if ((status & 0x10) == 0x00) { | 2607 | if ((status & 0x10) == 0x00) { |
2613 | dev->video_q.curr->top_seen = 1; | 2608 | dev->video_q.curr->top_seen = 1; |
2614 | goto done; | 2609 | goto done; |
2615 | } | 2610 | } |
2616 | if (!dev->video_q.curr->top_seen) | 2611 | if (!dev->video_q.curr->top_seen) |
2617 | goto done; | 2612 | goto done; |
2618 | } else if (field == V4L2_FIELD_TOP) { | 2613 | } else if (field == V4L2_FIELD_TOP) { |
2619 | if ((status & 0x10) != 0x10) | 2614 | if ((status & 0x10) != 0x10) |
2620 | goto done; | 2615 | goto done; |
2621 | } else if (field == V4L2_FIELD_BOTTOM) { | 2616 | } else if (field == V4L2_FIELD_BOTTOM) { |
2622 | if ((status & 0x10) != 0x00) | 2617 | if ((status & 0x10) != 0x00) |
2623 | goto done; | 2618 | goto done; |
2624 | } | 2619 | } |
2625 | dev->video_q.curr->vb.field_count = dev->video_fieldcount; | 2620 | dev->video_q.curr->vb.field_count = dev->video_fieldcount; |
2626 | saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); | 2621 | saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); |
2627 | } | 2622 | } |
2628 | saa7134_buffer_next(dev,&dev->video_q); | 2623 | saa7134_buffer_next(dev,&dev->video_q); |
2629 | 2624 | ||
2630 | done: | 2625 | done: |
2631 | spin_unlock(&dev->slock); | 2626 | spin_unlock(&dev->slock); |
2632 | } | 2627 | } |
2633 | 2628 | ||
2634 | /* ----------------------------------------------------------- */ | 2629 | /* ----------------------------------------------------------- */ |
2635 | /* | 2630 | /* |
2636 | * Local variables: | 2631 | * Local variables: |
2637 | * c-basic-offset: 8 | 2632 | * c-basic-offset: 8 |
2638 | * End: | 2633 | * End: |
2639 | */ | 2634 | */ |
2640 | 2635 |
drivers/media/video/saa7146.h
1 | /* | 1 | /* |
2 | saa7146.h - definitions philips saa7146 based cards | 2 | saa7146.h - definitions philips saa7146 based cards |
3 | Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) | 3 | Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or | 7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. | 8 | (at your option) any later version. |
9 | 9 | ||
10 | This program is distributed in the hope that it will be useful, | 10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. | 13 | GNU General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software | 16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef __SAA7146__ | 20 | #ifndef __SAA7146__ |
21 | #define __SAA7146__ | 21 | #define __SAA7146__ |
22 | 22 | ||
23 | #define SAA7146_VERSION_CODE 0x000101 | 23 | #define SAA7146_VERSION_CODE 0x000101 |
24 | 24 | ||
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/wait.h> | 26 | #include <linux/wait.h> |
27 | 27 | ||
28 | #include <linux/videodev.h> | ||
29 | |||
30 | #ifndef O_NONCAP | 28 | #ifndef O_NONCAP |
31 | #define O_NONCAP O_TRUNC | 29 | #define O_NONCAP O_TRUNC |
32 | #endif | 30 | #endif |
33 | 31 | ||
34 | #define MAX_GBUFFERS 2 | 32 | #define MAX_GBUFFERS 2 |
35 | #define FBUF_SIZE 0x190000 | 33 | #define FBUF_SIZE 0x190000 |
36 | 34 | ||
37 | #ifdef __KERNEL__ | 35 | #ifdef __KERNEL__ |
38 | 36 | ||
39 | struct saa7146_window | 37 | struct saa7146_window |
40 | { | 38 | { |
41 | int x, y; | 39 | int x, y; |
42 | ushort width, height; | 40 | ushort width, height; |
43 | ushort bpp, bpl; | 41 | ushort bpp, bpl; |
44 | ushort swidth, sheight; | 42 | ushort swidth, sheight; |
45 | short cropx, cropy; | 43 | short cropx, cropy; |
46 | ushort cropwidth, cropheight; | 44 | ushort cropwidth, cropheight; |
47 | unsigned long vidadr; | 45 | unsigned long vidadr; |
48 | int color_fmt; | 46 | int color_fmt; |
49 | ushort depth; | 47 | ushort depth; |
50 | }; | 48 | }; |
51 | 49 | ||
52 | /* Per-open data for handling multiple opens on one device */ | 50 | /* Per-open data for handling multiple opens on one device */ |
53 | struct device_open | 51 | struct device_open |
54 | { | 52 | { |
55 | int isopen; | 53 | int isopen; |
56 | int noncapturing; | 54 | int noncapturing; |
57 | struct saa7146 *dev; | 55 | struct saa7146 *dev; |
58 | }; | 56 | }; |
59 | #define MAX_OPENS 3 | 57 | #define MAX_OPENS 3 |
60 | 58 | ||
61 | struct saa7146 | 59 | struct saa7146 |
62 | { | 60 | { |
63 | struct video_device video_dev; | 61 | struct video_device video_dev; |
64 | struct video_picture picture; | 62 | struct video_picture picture; |
65 | struct video_audio audio_dev; | 63 | struct video_audio audio_dev; |
66 | struct video_info vidinfo; | 64 | struct video_info vidinfo; |
67 | int user; | 65 | int user; |
68 | int cap; | 66 | int cap; |
69 | int capuser; | 67 | int capuser; |
70 | int irqstate; /* irq routine is state driven */ | 68 | int irqstate; /* irq routine is state driven */ |
71 | int writemode; | 69 | int writemode; |
72 | int playmode; | 70 | int playmode; |
73 | unsigned int nr; | 71 | unsigned int nr; |
74 | unsigned long irq; /* IRQ used by SAA7146 card */ | 72 | unsigned long irq; /* IRQ used by SAA7146 card */ |
75 | unsigned short id; | 73 | unsigned short id; |
76 | unsigned char revision; | 74 | unsigned char revision; |
77 | unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ | 75 | unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ |
78 | unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ | 76 | unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ |
79 | struct saa7146_window win; | 77 | struct saa7146_window win; |
80 | unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */ | 78 | unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */ |
81 | struct device_open open_data[MAX_OPENS]; | 79 | struct device_open open_data[MAX_OPENS]; |
82 | #define MAX_MARKS 16 | 80 | #define MAX_MARKS 16 |
83 | /* for a/v sync */ | 81 | /* for a/v sync */ |
84 | int endmark[MAX_MARKS], endmarkhead, endmarktail; | 82 | int endmark[MAX_MARKS], endmarkhead, endmarktail; |
85 | u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, | 83 | u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, |
86 | *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, | 84 | *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, |
87 | *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, | 85 | *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, |
88 | *pagea1out, *pagea2in, *pagea2out; | 86 | *pagea1out, *pagea2in, *pagea2out; |
89 | wait_queue_head_t i2cq, debiq, audq, vidq; | 87 | wait_queue_head_t i2cq, debiq, audq, vidq; |
90 | u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; | 88 | u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; |
91 | int audhead, vidhead, osdhead, audtail, vidtail, osdtail; | 89 | int audhead, vidhead, osdhead, audtail, vidtail, osdtail; |
92 | spinlock_t lock; /* the device lock */ | 90 | spinlock_t lock; /* the device lock */ |
93 | }; | 91 | }; |
94 | #endif | 92 | #endif |
95 | 93 | ||
96 | #ifdef _ALPHA_SAA7146 | 94 | #ifdef _ALPHA_SAA7146 |
97 | #define saawrite(dat,adr) writel((dat), saa->saa7146_adr+(adr)) | 95 | #define saawrite(dat,adr) writel((dat), saa->saa7146_adr+(adr)) |
98 | #define saaread(adr) readl(saa->saa7146_adr+(adr)) | 96 | #define saaread(adr) readl(saa->saa7146_adr+(adr)) |
99 | #else | 97 | #else |
100 | #define saawrite(dat,adr) writel((dat), saa->saa7146_mem+(adr)) | 98 | #define saawrite(dat,adr) writel((dat), saa->saa7146_mem+(adr)) |
101 | #define saaread(adr) readl(saa->saa7146_mem+(adr)) | 99 | #define saaread(adr) readl(saa->saa7146_mem+(adr)) |
102 | #endif | 100 | #endif |
103 | 101 | ||
104 | #define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) | 102 | #define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) |
105 | #define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) | 103 | #define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) |
106 | #define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) | 104 | #define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) |
107 | 105 | ||
108 | /* bitmask of attached hardware found */ | 106 | /* bitmask of attached hardware found */ |
109 | #define SAA7146_UNKNOWN 0x00000000 | 107 | #define SAA7146_UNKNOWN 0x00000000 |
110 | #define SAA7146_SAA7111 0x00000001 | 108 | #define SAA7146_SAA7111 0x00000001 |
111 | #define SAA7146_SAA7121 0x00000002 | 109 | #define SAA7146_SAA7121 0x00000002 |
112 | #define SAA7146_IBMMPEG 0x00000004 | 110 | #define SAA7146_IBMMPEG 0x00000004 |
113 | 111 | ||
114 | #endif | 112 | #endif |
115 | 113 |
drivers/media/video/v4l2-ioctl.c
1 | /* | 1 | /* |
2 | * Video capture interface for Linux version 2 | 2 | * Video capture interface for Linux version 2 |
3 | * | 3 | * |
4 | * A generic framework to process V4L2 ioctl commands. | 4 | * A generic framework to process V4L2 ioctl commands. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | * | 10 | * |
11 | * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) | 11 | * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) |
12 | * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) | 12 | * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | 18 | ||
19 | #define __OLD_VIDIOC_ /* To allow fixing old calls */ | 19 | #define __OLD_VIDIOC_ /* To allow fixing old calls */ |
20 | #include <linux/videodev.h> | ||
20 | #include <linux/videodev2.h> | 21 | #include <linux/videodev2.h> |
21 | 22 | ||
22 | #ifdef CONFIG_VIDEO_V4L1 | 23 | #ifdef CONFIG_VIDEO_V4L1 |
23 | #include <linux/videodev.h> | 24 | #include <linux/videodev.h> |
24 | #endif | 25 | #endif |
25 | #include <media/v4l2-common.h> | 26 | #include <media/v4l2-common.h> |
26 | #include <media/v4l2-ioctl.h> | 27 | #include <media/v4l2-ioctl.h> |
27 | #include <media/v4l2-chip-ident.h> | 28 | #include <media/v4l2-chip-ident.h> |
28 | 29 | ||
29 | #define dbgarg(cmd, fmt, arg...) \ | 30 | #define dbgarg(cmd, fmt, arg...) \ |
30 | do { \ | 31 | do { \ |
31 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ | 32 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ |
32 | printk(KERN_DEBUG "%s: ", vfd->name); \ | 33 | printk(KERN_DEBUG "%s: ", vfd->name); \ |
33 | v4l_printk_ioctl(cmd); \ | 34 | v4l_printk_ioctl(cmd); \ |
34 | printk(" " fmt, ## arg); \ | 35 | printk(" " fmt, ## arg); \ |
35 | } \ | 36 | } \ |
36 | } while (0) | 37 | } while (0) |
37 | 38 | ||
38 | #define dbgarg2(fmt, arg...) \ | 39 | #define dbgarg2(fmt, arg...) \ |
39 | do { \ | 40 | do { \ |
40 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ | 41 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ |
41 | printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ | 42 | printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ |
42 | } while (0) | 43 | } while (0) |
43 | 44 | ||
44 | struct std_descr { | 45 | struct std_descr { |
45 | v4l2_std_id std; | 46 | v4l2_std_id std; |
46 | const char *descr; | 47 | const char *descr; |
47 | }; | 48 | }; |
48 | 49 | ||
49 | static const struct std_descr standards[] = { | 50 | static const struct std_descr standards[] = { |
50 | { V4L2_STD_NTSC, "NTSC" }, | 51 | { V4L2_STD_NTSC, "NTSC" }, |
51 | { V4L2_STD_NTSC_M, "NTSC-M" }, | 52 | { V4L2_STD_NTSC_M, "NTSC-M" }, |
52 | { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, | 53 | { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, |
53 | { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, | 54 | { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, |
54 | { V4L2_STD_NTSC_443, "NTSC-443" }, | 55 | { V4L2_STD_NTSC_443, "NTSC-443" }, |
55 | { V4L2_STD_PAL, "PAL" }, | 56 | { V4L2_STD_PAL, "PAL" }, |
56 | { V4L2_STD_PAL_BG, "PAL-BG" }, | 57 | { V4L2_STD_PAL_BG, "PAL-BG" }, |
57 | { V4L2_STD_PAL_B, "PAL-B" }, | 58 | { V4L2_STD_PAL_B, "PAL-B" }, |
58 | { V4L2_STD_PAL_B1, "PAL-B1" }, | 59 | { V4L2_STD_PAL_B1, "PAL-B1" }, |
59 | { V4L2_STD_PAL_G, "PAL-G" }, | 60 | { V4L2_STD_PAL_G, "PAL-G" }, |
60 | { V4L2_STD_PAL_H, "PAL-H" }, | 61 | { V4L2_STD_PAL_H, "PAL-H" }, |
61 | { V4L2_STD_PAL_I, "PAL-I" }, | 62 | { V4L2_STD_PAL_I, "PAL-I" }, |
62 | { V4L2_STD_PAL_DK, "PAL-DK" }, | 63 | { V4L2_STD_PAL_DK, "PAL-DK" }, |
63 | { V4L2_STD_PAL_D, "PAL-D" }, | 64 | { V4L2_STD_PAL_D, "PAL-D" }, |
64 | { V4L2_STD_PAL_D1, "PAL-D1" }, | 65 | { V4L2_STD_PAL_D1, "PAL-D1" }, |
65 | { V4L2_STD_PAL_K, "PAL-K" }, | 66 | { V4L2_STD_PAL_K, "PAL-K" }, |
66 | { V4L2_STD_PAL_M, "PAL-M" }, | 67 | { V4L2_STD_PAL_M, "PAL-M" }, |
67 | { V4L2_STD_PAL_N, "PAL-N" }, | 68 | { V4L2_STD_PAL_N, "PAL-N" }, |
68 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, | 69 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, |
69 | { V4L2_STD_PAL_60, "PAL-60" }, | 70 | { V4L2_STD_PAL_60, "PAL-60" }, |
70 | { V4L2_STD_SECAM, "SECAM" }, | 71 | { V4L2_STD_SECAM, "SECAM" }, |
71 | { V4L2_STD_SECAM_B, "SECAM-B" }, | 72 | { V4L2_STD_SECAM_B, "SECAM-B" }, |
72 | { V4L2_STD_SECAM_G, "SECAM-G" }, | 73 | { V4L2_STD_SECAM_G, "SECAM-G" }, |
73 | { V4L2_STD_SECAM_H, "SECAM-H" }, | 74 | { V4L2_STD_SECAM_H, "SECAM-H" }, |
74 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, | 75 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, |
75 | { V4L2_STD_SECAM_D, "SECAM-D" }, | 76 | { V4L2_STD_SECAM_D, "SECAM-D" }, |
76 | { V4L2_STD_SECAM_K, "SECAM-K" }, | 77 | { V4L2_STD_SECAM_K, "SECAM-K" }, |
77 | { V4L2_STD_SECAM_K1, "SECAM-K1" }, | 78 | { V4L2_STD_SECAM_K1, "SECAM-K1" }, |
78 | { V4L2_STD_SECAM_L, "SECAM-L" }, | 79 | { V4L2_STD_SECAM_L, "SECAM-L" }, |
79 | { V4L2_STD_SECAM_LC, "SECAM-Lc" }, | 80 | { V4L2_STD_SECAM_LC, "SECAM-Lc" }, |
80 | { 0, "Unknown" } | 81 | { 0, "Unknown" } |
81 | }; | 82 | }; |
82 | 83 | ||
83 | /* video4linux standard ID conversion to standard name | 84 | /* video4linux standard ID conversion to standard name |
84 | */ | 85 | */ |
85 | const char *v4l2_norm_to_name(v4l2_std_id id) | 86 | const char *v4l2_norm_to_name(v4l2_std_id id) |
86 | { | 87 | { |
87 | u32 myid = id; | 88 | u32 myid = id; |
88 | int i; | 89 | int i; |
89 | 90 | ||
90 | /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle | 91 | /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle |
91 | 64 bit comparations. So, on that architecture, with some gcc | 92 | 64 bit comparations. So, on that architecture, with some gcc |
92 | variants, compilation fails. Currently, the max value is 30bit wide. | 93 | variants, compilation fails. Currently, the max value is 30bit wide. |
93 | */ | 94 | */ |
94 | BUG_ON(myid != id); | 95 | BUG_ON(myid != id); |
95 | 96 | ||
96 | for (i = 0; standards[i].std; i++) | 97 | for (i = 0; standards[i].std; i++) |
97 | if (myid == standards[i].std) | 98 | if (myid == standards[i].std) |
98 | break; | 99 | break; |
99 | return standards[i].descr; | 100 | return standards[i].descr; |
100 | } | 101 | } |
101 | EXPORT_SYMBOL(v4l2_norm_to_name); | 102 | EXPORT_SYMBOL(v4l2_norm_to_name); |
102 | 103 | ||
103 | /* Returns frame period for the given standard */ | 104 | /* Returns frame period for the given standard */ |
104 | void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod) | 105 | void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod) |
105 | { | 106 | { |
106 | if (id & V4L2_STD_525_60) { | 107 | if (id & V4L2_STD_525_60) { |
107 | frameperiod->numerator = 1001; | 108 | frameperiod->numerator = 1001; |
108 | frameperiod->denominator = 30000; | 109 | frameperiod->denominator = 30000; |
109 | } else { | 110 | } else { |
110 | frameperiod->numerator = 1; | 111 | frameperiod->numerator = 1; |
111 | frameperiod->denominator = 25; | 112 | frameperiod->denominator = 25; |
112 | } | 113 | } |
113 | } | 114 | } |
114 | EXPORT_SYMBOL(v4l2_video_std_frame_period); | 115 | EXPORT_SYMBOL(v4l2_video_std_frame_period); |
115 | 116 | ||
116 | /* Fill in the fields of a v4l2_standard structure according to the | 117 | /* Fill in the fields of a v4l2_standard structure according to the |
117 | 'id' and 'transmission' parameters. Returns negative on error. */ | 118 | 'id' and 'transmission' parameters. Returns negative on error. */ |
118 | int v4l2_video_std_construct(struct v4l2_standard *vs, | 119 | int v4l2_video_std_construct(struct v4l2_standard *vs, |
119 | int id, const char *name) | 120 | int id, const char *name) |
120 | { | 121 | { |
121 | vs->id = id; | 122 | vs->id = id; |
122 | v4l2_video_std_frame_period(id, &vs->frameperiod); | 123 | v4l2_video_std_frame_period(id, &vs->frameperiod); |
123 | vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625; | 124 | vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625; |
124 | strlcpy(vs->name, name, sizeof(vs->name)); | 125 | strlcpy(vs->name, name, sizeof(vs->name)); |
125 | return 0; | 126 | return 0; |
126 | } | 127 | } |
127 | EXPORT_SYMBOL(v4l2_video_std_construct); | 128 | EXPORT_SYMBOL(v4l2_video_std_construct); |
128 | 129 | ||
129 | /* ----------------------------------------------------------------- */ | 130 | /* ----------------------------------------------------------------- */ |
130 | /* some arrays for pretty-printing debug messages of enum types */ | 131 | /* some arrays for pretty-printing debug messages of enum types */ |
131 | 132 | ||
132 | const char *v4l2_field_names[] = { | 133 | const char *v4l2_field_names[] = { |
133 | [V4L2_FIELD_ANY] = "any", | 134 | [V4L2_FIELD_ANY] = "any", |
134 | [V4L2_FIELD_NONE] = "none", | 135 | [V4L2_FIELD_NONE] = "none", |
135 | [V4L2_FIELD_TOP] = "top", | 136 | [V4L2_FIELD_TOP] = "top", |
136 | [V4L2_FIELD_BOTTOM] = "bottom", | 137 | [V4L2_FIELD_BOTTOM] = "bottom", |
137 | [V4L2_FIELD_INTERLACED] = "interlaced", | 138 | [V4L2_FIELD_INTERLACED] = "interlaced", |
138 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | 139 | [V4L2_FIELD_SEQ_TB] = "seq-tb", |
139 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | 140 | [V4L2_FIELD_SEQ_BT] = "seq-bt", |
140 | [V4L2_FIELD_ALTERNATE] = "alternate", | 141 | [V4L2_FIELD_ALTERNATE] = "alternate", |
141 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | 142 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", |
142 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | 143 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", |
143 | }; | 144 | }; |
144 | EXPORT_SYMBOL(v4l2_field_names); | 145 | EXPORT_SYMBOL(v4l2_field_names); |
145 | 146 | ||
146 | const char *v4l2_type_names[] = { | 147 | const char *v4l2_type_names[] = { |
147 | [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", | 148 | [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", |
148 | [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", | 149 | [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", |
149 | [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", | 150 | [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", |
150 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", | 151 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", |
151 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | 152 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", |
152 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", | 153 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", |
153 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | 154 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
154 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", | 155 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", |
155 | }; | 156 | }; |
156 | EXPORT_SYMBOL(v4l2_type_names); | 157 | EXPORT_SYMBOL(v4l2_type_names); |
157 | 158 | ||
158 | static const char *v4l2_memory_names[] = { | 159 | static const char *v4l2_memory_names[] = { |
159 | [V4L2_MEMORY_MMAP] = "mmap", | 160 | [V4L2_MEMORY_MMAP] = "mmap", |
160 | [V4L2_MEMORY_USERPTR] = "userptr", | 161 | [V4L2_MEMORY_USERPTR] = "userptr", |
161 | [V4L2_MEMORY_OVERLAY] = "overlay", | 162 | [V4L2_MEMORY_OVERLAY] = "overlay", |
162 | }; | 163 | }; |
163 | 164 | ||
164 | #define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ | 165 | #define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ |
165 | arr[a] : "unknown") | 166 | arr[a] : "unknown") |
166 | 167 | ||
167 | /* ------------------------------------------------------------------ */ | 168 | /* ------------------------------------------------------------------ */ |
168 | /* debug help functions */ | 169 | /* debug help functions */ |
169 | 170 | ||
170 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 171 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
171 | static const char *v4l1_ioctls[] = { | 172 | static const char *v4l1_ioctls[] = { |
172 | [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", | 173 | [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", |
173 | [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", | 174 | [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", |
174 | [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", | 175 | [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", |
175 | [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", | 176 | [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", |
176 | [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", | 177 | [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", |
177 | [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", | 178 | [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", |
178 | [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", | 179 | [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", |
179 | [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", | 180 | [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", |
180 | [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", | 181 | [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", |
181 | [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", | 182 | [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", |
182 | [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", | 183 | [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", |
183 | [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", | 184 | [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", |
184 | [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", | 185 | [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", |
185 | [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", | 186 | [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", |
186 | [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", | 187 | [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", |
187 | [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", | 188 | [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", |
188 | [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", | 189 | [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", |
189 | [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", | 190 | [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", |
190 | [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", | 191 | [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", |
191 | [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", | 192 | [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", |
192 | [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", | 193 | [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", |
193 | [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", | 194 | [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", |
194 | [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", | 195 | [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", |
195 | [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", | 196 | [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", |
196 | [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", | 197 | [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", |
197 | [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", | 198 | [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", |
198 | [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", | 199 | [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", |
199 | [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", | 200 | [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", |
200 | [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" | 201 | [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" |
201 | }; | 202 | }; |
202 | #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) | 203 | #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) |
203 | #endif | 204 | #endif |
204 | 205 | ||
205 | static const char *v4l2_ioctls[] = { | 206 | static const char *v4l2_ioctls[] = { |
206 | [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", | 207 | [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", |
207 | [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", | 208 | [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", |
208 | [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", | 209 | [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", |
209 | [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", | 210 | [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", |
210 | [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", | 211 | [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", |
211 | [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", | 212 | [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", |
212 | [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", | 213 | [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", |
213 | [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", | 214 | [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", |
214 | [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", | 215 | [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", |
215 | [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", | 216 | [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", |
216 | [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", | 217 | [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", |
217 | [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", | 218 | [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", |
218 | [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", | 219 | [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", |
219 | [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", | 220 | [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", |
220 | [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", | 221 | [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", |
221 | [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", | 222 | [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", |
222 | [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", | 223 | [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", |
223 | [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", | 224 | [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", |
224 | [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", | 225 | [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", |
225 | [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", | 226 | [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", |
226 | [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", | 227 | [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", |
227 | [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", | 228 | [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", |
228 | [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", | 229 | [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", |
229 | [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", | 230 | [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", |
230 | [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", | 231 | [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", |
231 | [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", | 232 | [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", |
232 | [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", | 233 | [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", |
233 | [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", | 234 | [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", |
234 | [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", | 235 | [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", |
235 | [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", | 236 | [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", |
236 | [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", | 237 | [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", |
237 | [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", | 238 | [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", |
238 | [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", | 239 | [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", |
239 | [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", | 240 | [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", |
240 | [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", | 241 | [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", |
241 | [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", | 242 | [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", |
242 | [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", | 243 | [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", |
243 | [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", | 244 | [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", |
244 | [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", | 245 | [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", |
245 | [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", | 246 | [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", |
246 | [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", | 247 | [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", |
247 | [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", | 248 | [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", |
248 | [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", | 249 | [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", |
249 | [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", | 250 | [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", |
250 | [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", | 251 | [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", |
251 | [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", | 252 | [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", |
252 | [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", | 253 | [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", |
253 | [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", | 254 | [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", |
254 | [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", | 255 | [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", |
255 | [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", | 256 | [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", |
256 | [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", | 257 | [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", |
257 | [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", | 258 | [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", |
258 | [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", | 259 | [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", |
259 | [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", | 260 | [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", |
260 | [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", | 261 | [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", |
261 | #if 1 | 262 | #if 1 |
262 | [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", | 263 | [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", |
263 | [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", | 264 | [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", |
264 | [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", | 265 | [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", |
265 | [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", | 266 | [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", |
266 | [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", | 267 | [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", |
267 | 268 | ||
268 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", | 269 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", |
269 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", | 270 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", |
270 | 271 | ||
271 | [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", | 272 | [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", |
272 | [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", | 273 | [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", |
273 | #endif | 274 | #endif |
274 | }; | 275 | }; |
275 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 276 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
276 | 277 | ||
277 | static const char *v4l2_int_ioctls[] = { | 278 | static const char *v4l2_int_ioctls[] = { |
278 | [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", | 279 | [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", |
279 | 280 | ||
280 | [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", | 281 | [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", |
281 | [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", | 282 | [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", |
282 | [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", | 283 | [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", |
283 | 284 | ||
284 | [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", | 285 | [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", |
285 | [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", | 286 | [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", |
286 | [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", | 287 | [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", |
287 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", | 288 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", |
288 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", | 289 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", |
289 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", | 290 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", |
290 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", | 291 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", |
291 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", | 292 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", |
292 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", | 293 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", |
293 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", | 294 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", |
294 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", | 295 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", |
295 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", | 296 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", |
296 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", | 297 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", |
297 | [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", | 298 | [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", |
298 | [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", | 299 | [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", |
299 | [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", | 300 | [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", |
300 | }; | 301 | }; |
301 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) | 302 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) |
302 | 303 | ||
303 | /* Common ioctl debug function. This function can be used by | 304 | /* Common ioctl debug function. This function can be used by |
304 | external ioctl messages as well as internal V4L ioctl */ | 305 | external ioctl messages as well as internal V4L ioctl */ |
305 | void v4l_printk_ioctl(unsigned int cmd) | 306 | void v4l_printk_ioctl(unsigned int cmd) |
306 | { | 307 | { |
307 | char *dir, *type; | 308 | char *dir, *type; |
308 | 309 | ||
309 | switch (_IOC_TYPE(cmd)) { | 310 | switch (_IOC_TYPE(cmd)) { |
310 | case 'd': | 311 | case 'd': |
311 | if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { | 312 | if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { |
312 | type = "v4l2_int"; | 313 | type = "v4l2_int"; |
313 | break; | 314 | break; |
314 | } | 315 | } |
315 | printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); | 316 | printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); |
316 | return; | 317 | return; |
317 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 318 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
318 | case 'v': | 319 | case 'v': |
319 | if (_IOC_NR(cmd) >= V4L1_IOCTLS) { | 320 | if (_IOC_NR(cmd) >= V4L1_IOCTLS) { |
320 | type = "v4l1"; | 321 | type = "v4l1"; |
321 | break; | 322 | break; |
322 | } | 323 | } |
323 | printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); | 324 | printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); |
324 | return; | 325 | return; |
325 | #endif | 326 | #endif |
326 | case 'V': | 327 | case 'V': |
327 | if (_IOC_NR(cmd) >= V4L2_IOCTLS) { | 328 | if (_IOC_NR(cmd) >= V4L2_IOCTLS) { |
328 | type = "v4l2"; | 329 | type = "v4l2"; |
329 | break; | 330 | break; |
330 | } | 331 | } |
331 | printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); | 332 | printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); |
332 | return; | 333 | return; |
333 | default: | 334 | default: |
334 | type = "unknown"; | 335 | type = "unknown"; |
335 | } | 336 | } |
336 | 337 | ||
337 | switch (_IOC_DIR(cmd)) { | 338 | switch (_IOC_DIR(cmd)) { |
338 | case _IOC_NONE: dir = "--"; break; | 339 | case _IOC_NONE: dir = "--"; break; |
339 | case _IOC_READ: dir = "r-"; break; | 340 | case _IOC_READ: dir = "r-"; break; |
340 | case _IOC_WRITE: dir = "-w"; break; | 341 | case _IOC_WRITE: dir = "-w"; break; |
341 | case _IOC_READ | _IOC_WRITE: dir = "rw"; break; | 342 | case _IOC_READ | _IOC_WRITE: dir = "rw"; break; |
342 | default: dir = "*ERR*"; break; | 343 | default: dir = "*ERR*"; break; |
343 | } | 344 | } |
344 | printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", | 345 | printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", |
345 | type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); | 346 | type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); |
346 | } | 347 | } |
347 | EXPORT_SYMBOL(v4l_printk_ioctl); | 348 | EXPORT_SYMBOL(v4l_printk_ioctl); |
348 | 349 | ||
349 | /* | 350 | /* |
350 | * helper function -- handles userspace copying for ioctl arguments | 351 | * helper function -- handles userspace copying for ioctl arguments |
351 | */ | 352 | */ |
352 | 353 | ||
353 | #ifdef __OLD_VIDIOC_ | 354 | #ifdef __OLD_VIDIOC_ |
354 | static unsigned int | 355 | static unsigned int |
355 | video_fix_command(unsigned int cmd) | 356 | video_fix_command(unsigned int cmd) |
356 | { | 357 | { |
357 | switch (cmd) { | 358 | switch (cmd) { |
358 | case VIDIOC_OVERLAY_OLD: | 359 | case VIDIOC_OVERLAY_OLD: |
359 | cmd = VIDIOC_OVERLAY; | 360 | cmd = VIDIOC_OVERLAY; |
360 | break; | 361 | break; |
361 | case VIDIOC_S_PARM_OLD: | 362 | case VIDIOC_S_PARM_OLD: |
362 | cmd = VIDIOC_S_PARM; | 363 | cmd = VIDIOC_S_PARM; |
363 | break; | 364 | break; |
364 | case VIDIOC_S_CTRL_OLD: | 365 | case VIDIOC_S_CTRL_OLD: |
365 | cmd = VIDIOC_S_CTRL; | 366 | cmd = VIDIOC_S_CTRL; |
366 | break; | 367 | break; |
367 | case VIDIOC_G_AUDIO_OLD: | 368 | case VIDIOC_G_AUDIO_OLD: |
368 | cmd = VIDIOC_G_AUDIO; | 369 | cmd = VIDIOC_G_AUDIO; |
369 | break; | 370 | break; |
370 | case VIDIOC_G_AUDOUT_OLD: | 371 | case VIDIOC_G_AUDOUT_OLD: |
371 | cmd = VIDIOC_G_AUDOUT; | 372 | cmd = VIDIOC_G_AUDOUT; |
372 | break; | 373 | break; |
373 | case VIDIOC_CROPCAP_OLD: | 374 | case VIDIOC_CROPCAP_OLD: |
374 | cmd = VIDIOC_CROPCAP; | 375 | cmd = VIDIOC_CROPCAP; |
375 | break; | 376 | break; |
376 | } | 377 | } |
377 | return cmd; | 378 | return cmd; |
378 | } | 379 | } |
379 | #endif | 380 | #endif |
380 | 381 | ||
381 | /* | 382 | /* |
382 | * Obsolete usercopy function - Should be removed soon | 383 | * Obsolete usercopy function - Should be removed soon |
383 | */ | 384 | */ |
384 | long | 385 | long |
385 | video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | 386 | video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, |
386 | v4l2_kioctl func) | 387 | v4l2_kioctl func) |
387 | { | 388 | { |
388 | char sbuf[128]; | 389 | char sbuf[128]; |
389 | void *mbuf = NULL; | 390 | void *mbuf = NULL; |
390 | void *parg = NULL; | 391 | void *parg = NULL; |
391 | long err = -EINVAL; | 392 | long err = -EINVAL; |
392 | int is_ext_ctrl; | 393 | int is_ext_ctrl; |
393 | size_t ctrls_size = 0; | 394 | size_t ctrls_size = 0; |
394 | void __user *user_ptr = NULL; | 395 | void __user *user_ptr = NULL; |
395 | 396 | ||
396 | #ifdef __OLD_VIDIOC_ | 397 | #ifdef __OLD_VIDIOC_ |
397 | cmd = video_fix_command(cmd); | 398 | cmd = video_fix_command(cmd); |
398 | #endif | 399 | #endif |
399 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | 400 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || |
400 | cmd == VIDIOC_TRY_EXT_CTRLS); | 401 | cmd == VIDIOC_TRY_EXT_CTRLS); |
401 | 402 | ||
402 | /* Copy arguments into temp kernel buffer */ | 403 | /* Copy arguments into temp kernel buffer */ |
403 | switch (_IOC_DIR(cmd)) { | 404 | switch (_IOC_DIR(cmd)) { |
404 | case _IOC_NONE: | 405 | case _IOC_NONE: |
405 | parg = NULL; | 406 | parg = NULL; |
406 | break; | 407 | break; |
407 | case _IOC_READ: | 408 | case _IOC_READ: |
408 | case _IOC_WRITE: | 409 | case _IOC_WRITE: |
409 | case (_IOC_WRITE | _IOC_READ): | 410 | case (_IOC_WRITE | _IOC_READ): |
410 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | 411 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { |
411 | parg = sbuf; | 412 | parg = sbuf; |
412 | } else { | 413 | } else { |
413 | /* too big to allocate from stack */ | 414 | /* too big to allocate from stack */ |
414 | mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); | 415 | mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); |
415 | if (NULL == mbuf) | 416 | if (NULL == mbuf) |
416 | return -ENOMEM; | 417 | return -ENOMEM; |
417 | parg = mbuf; | 418 | parg = mbuf; |
418 | } | 419 | } |
419 | 420 | ||
420 | err = -EFAULT; | 421 | err = -EFAULT; |
421 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 422 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
422 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | 423 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) |
423 | goto out; | 424 | goto out; |
424 | break; | 425 | break; |
425 | } | 426 | } |
426 | if (is_ext_ctrl) { | 427 | if (is_ext_ctrl) { |
427 | struct v4l2_ext_controls *p = parg; | 428 | struct v4l2_ext_controls *p = parg; |
428 | 429 | ||
429 | /* In case of an error, tell the caller that it wasn't | 430 | /* In case of an error, tell the caller that it wasn't |
430 | a specific control that caused it. */ | 431 | a specific control that caused it. */ |
431 | p->error_idx = p->count; | 432 | p->error_idx = p->count; |
432 | user_ptr = (void __user *)p->controls; | 433 | user_ptr = (void __user *)p->controls; |
433 | if (p->count) { | 434 | if (p->count) { |
434 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | 435 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; |
435 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | 436 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ |
436 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | 437 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); |
437 | err = -ENOMEM; | 438 | err = -ENOMEM; |
438 | if (NULL == mbuf) | 439 | if (NULL == mbuf) |
439 | goto out_ext_ctrl; | 440 | goto out_ext_ctrl; |
440 | err = -EFAULT; | 441 | err = -EFAULT; |
441 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | 442 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) |
442 | goto out_ext_ctrl; | 443 | goto out_ext_ctrl; |
443 | p->controls = mbuf; | 444 | p->controls = mbuf; |
444 | } | 445 | } |
445 | } | 446 | } |
446 | 447 | ||
447 | /* call driver */ | 448 | /* call driver */ |
448 | err = func(file, cmd, parg); | 449 | err = func(file, cmd, parg); |
449 | if (err == -ENOIOCTLCMD) | 450 | if (err == -ENOIOCTLCMD) |
450 | err = -EINVAL; | 451 | err = -EINVAL; |
451 | if (is_ext_ctrl) { | 452 | if (is_ext_ctrl) { |
452 | struct v4l2_ext_controls *p = parg; | 453 | struct v4l2_ext_controls *p = parg; |
453 | 454 | ||
454 | p->controls = (void *)user_ptr; | 455 | p->controls = (void *)user_ptr; |
455 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | 456 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) |
456 | err = -EFAULT; | 457 | err = -EFAULT; |
457 | goto out_ext_ctrl; | 458 | goto out_ext_ctrl; |
458 | } | 459 | } |
459 | if (err < 0) | 460 | if (err < 0) |
460 | goto out; | 461 | goto out; |
461 | 462 | ||
462 | out_ext_ctrl: | 463 | out_ext_ctrl: |
463 | /* Copy results into user buffer */ | 464 | /* Copy results into user buffer */ |
464 | switch (_IOC_DIR(cmd)) { | 465 | switch (_IOC_DIR(cmd)) { |
465 | case _IOC_READ: | 466 | case _IOC_READ: |
466 | case (_IOC_WRITE | _IOC_READ): | 467 | case (_IOC_WRITE | _IOC_READ): |
467 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | 468 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) |
468 | err = -EFAULT; | 469 | err = -EFAULT; |
469 | break; | 470 | break; |
470 | } | 471 | } |
471 | 472 | ||
472 | out: | 473 | out: |
473 | kfree(mbuf); | 474 | kfree(mbuf); |
474 | return err; | 475 | return err; |
475 | } | 476 | } |
476 | EXPORT_SYMBOL(video_usercopy); | 477 | EXPORT_SYMBOL(video_usercopy); |
477 | 478 | ||
478 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, | 479 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, |
479 | struct v4l2_buffer *p) | 480 | struct v4l2_buffer *p) |
480 | { | 481 | { |
481 | struct v4l2_timecode *tc = &p->timecode; | 482 | struct v4l2_timecode *tc = &p->timecode; |
482 | 483 | ||
483 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " | 484 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " |
484 | "bytesused=%d, flags=0x%08d, " | 485 | "bytesused=%d, flags=0x%08d, " |
485 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", | 486 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", |
486 | p->timestamp.tv_sec / 3600, | 487 | p->timestamp.tv_sec / 3600, |
487 | (int)(p->timestamp.tv_sec / 60) % 60, | 488 | (int)(p->timestamp.tv_sec / 60) % 60, |
488 | (int)(p->timestamp.tv_sec % 60), | 489 | (int)(p->timestamp.tv_sec % 60), |
489 | (long)p->timestamp.tv_usec, | 490 | (long)p->timestamp.tv_usec, |
490 | p->index, | 491 | p->index, |
491 | prt_names(p->type, v4l2_type_names), | 492 | prt_names(p->type, v4l2_type_names), |
492 | p->bytesused, p->flags, | 493 | p->bytesused, p->flags, |
493 | p->field, p->sequence, | 494 | p->field, p->sequence, |
494 | prt_names(p->memory, v4l2_memory_names), | 495 | prt_names(p->memory, v4l2_memory_names), |
495 | p->m.userptr, p->length); | 496 | p->m.userptr, p->length); |
496 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " | 497 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " |
497 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", | 498 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", |
498 | tc->hours, tc->minutes, tc->seconds, | 499 | tc->hours, tc->minutes, tc->seconds, |
499 | tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); | 500 | tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); |
500 | } | 501 | } |
501 | 502 | ||
502 | static inline void dbgrect(struct video_device *vfd, char *s, | 503 | static inline void dbgrect(struct video_device *vfd, char *s, |
503 | struct v4l2_rect *r) | 504 | struct v4l2_rect *r) |
504 | { | 505 | { |
505 | dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, | 506 | dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, |
506 | r->width, r->height); | 507 | r->width, r->height); |
507 | }; | 508 | }; |
508 | 509 | ||
509 | static inline void v4l_print_pix_fmt(struct video_device *vfd, | 510 | static inline void v4l_print_pix_fmt(struct video_device *vfd, |
510 | struct v4l2_pix_format *fmt) | 511 | struct v4l2_pix_format *fmt) |
511 | { | 512 | { |
512 | dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " | 513 | dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " |
513 | "bytesperline=%d sizeimage=%d, colorspace=%d\n", | 514 | "bytesperline=%d sizeimage=%d, colorspace=%d\n", |
514 | fmt->width, fmt->height, | 515 | fmt->width, fmt->height, |
515 | (fmt->pixelformat & 0xff), | 516 | (fmt->pixelformat & 0xff), |
516 | (fmt->pixelformat >> 8) & 0xff, | 517 | (fmt->pixelformat >> 8) & 0xff, |
517 | (fmt->pixelformat >> 16) & 0xff, | 518 | (fmt->pixelformat >> 16) & 0xff, |
518 | (fmt->pixelformat >> 24) & 0xff, | 519 | (fmt->pixelformat >> 24) & 0xff, |
519 | prt_names(fmt->field, v4l2_field_names), | 520 | prt_names(fmt->field, v4l2_field_names), |
520 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); | 521 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); |
521 | }; | 522 | }; |
522 | 523 | ||
523 | static inline void v4l_print_ext_ctrls(unsigned int cmd, | 524 | static inline void v4l_print_ext_ctrls(unsigned int cmd, |
524 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) | 525 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) |
525 | { | 526 | { |
526 | __u32 i; | 527 | __u32 i; |
527 | 528 | ||
528 | if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) | 529 | if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) |
529 | return; | 530 | return; |
530 | dbgarg(cmd, ""); | 531 | dbgarg(cmd, ""); |
531 | printk(KERN_CONT "class=0x%x", c->ctrl_class); | 532 | printk(KERN_CONT "class=0x%x", c->ctrl_class); |
532 | for (i = 0; i < c->count; i++) { | 533 | for (i = 0; i < c->count; i++) { |
533 | if (show_vals) | 534 | if (show_vals) |
534 | printk(KERN_CONT " id/val=0x%x/0x%x", | 535 | printk(KERN_CONT " id/val=0x%x/0x%x", |
535 | c->controls[i].id, c->controls[i].value); | 536 | c->controls[i].id, c->controls[i].value); |
536 | else | 537 | else |
537 | printk(KERN_CONT " id=0x%x", c->controls[i].id); | 538 | printk(KERN_CONT " id=0x%x", c->controls[i].id); |
538 | } | 539 | } |
539 | printk(KERN_CONT "\n"); | 540 | printk(KERN_CONT "\n"); |
540 | }; | 541 | }; |
541 | 542 | ||
542 | static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) | 543 | static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) |
543 | { | 544 | { |
544 | __u32 i; | 545 | __u32 i; |
545 | 546 | ||
546 | /* zero the reserved fields */ | 547 | /* zero the reserved fields */ |
547 | c->reserved[0] = c->reserved[1] = 0; | 548 | c->reserved[0] = c->reserved[1] = 0; |
548 | for (i = 0; i < c->count; i++) { | 549 | for (i = 0; i < c->count; i++) { |
549 | c->controls[i].reserved2[0] = 0; | 550 | c->controls[i].reserved2[0] = 0; |
550 | c->controls[i].reserved2[1] = 0; | 551 | c->controls[i].reserved2[1] = 0; |
551 | } | 552 | } |
552 | /* V4L2_CID_PRIVATE_BASE cannot be used as control class | 553 | /* V4L2_CID_PRIVATE_BASE cannot be used as control class |
553 | when using extended controls. | 554 | when using extended controls. |
554 | Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL | 555 | Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL |
555 | is it allowed for backwards compatibility. | 556 | is it allowed for backwards compatibility. |
556 | */ | 557 | */ |
557 | if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) | 558 | if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) |
558 | return 0; | 559 | return 0; |
559 | /* Check that all controls are from the same control class. */ | 560 | /* Check that all controls are from the same control class. */ |
560 | for (i = 0; i < c->count; i++) { | 561 | for (i = 0; i < c->count; i++) { |
561 | if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { | 562 | if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { |
562 | c->error_idx = i; | 563 | c->error_idx = i; |
563 | return 0; | 564 | return 0; |
564 | } | 565 | } |
565 | } | 566 | } |
566 | return 1; | 567 | return 1; |
567 | } | 568 | } |
568 | 569 | ||
569 | static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | 570 | static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) |
570 | { | 571 | { |
571 | if (ops == NULL) | 572 | if (ops == NULL) |
572 | return -EINVAL; | 573 | return -EINVAL; |
573 | 574 | ||
574 | switch (type) { | 575 | switch (type) { |
575 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 576 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
576 | if (ops->vidioc_try_fmt_vid_cap) | 577 | if (ops->vidioc_try_fmt_vid_cap) |
577 | return 0; | 578 | return 0; |
578 | break; | 579 | break; |
579 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 580 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
580 | if (ops->vidioc_try_fmt_vid_overlay) | 581 | if (ops->vidioc_try_fmt_vid_overlay) |
581 | return 0; | 582 | return 0; |
582 | break; | 583 | break; |
583 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 584 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
584 | if (ops->vidioc_try_fmt_vid_out) | 585 | if (ops->vidioc_try_fmt_vid_out) |
585 | return 0; | 586 | return 0; |
586 | break; | 587 | break; |
587 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 588 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
588 | if (ops->vidioc_try_fmt_vid_out_overlay) | 589 | if (ops->vidioc_try_fmt_vid_out_overlay) |
589 | return 0; | 590 | return 0; |
590 | break; | 591 | break; |
591 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 592 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
592 | if (ops->vidioc_try_fmt_vbi_cap) | 593 | if (ops->vidioc_try_fmt_vbi_cap) |
593 | return 0; | 594 | return 0; |
594 | break; | 595 | break; |
595 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 596 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
596 | if (ops->vidioc_try_fmt_vbi_out) | 597 | if (ops->vidioc_try_fmt_vbi_out) |
597 | return 0; | 598 | return 0; |
598 | break; | 599 | break; |
599 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 600 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
600 | if (ops->vidioc_try_fmt_sliced_vbi_cap) | 601 | if (ops->vidioc_try_fmt_sliced_vbi_cap) |
601 | return 0; | 602 | return 0; |
602 | break; | 603 | break; |
603 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | 604 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: |
604 | if (ops->vidioc_try_fmt_sliced_vbi_out) | 605 | if (ops->vidioc_try_fmt_sliced_vbi_out) |
605 | return 0; | 606 | return 0; |
606 | break; | 607 | break; |
607 | case V4L2_BUF_TYPE_PRIVATE: | 608 | case V4L2_BUF_TYPE_PRIVATE: |
608 | if (ops->vidioc_try_fmt_type_private) | 609 | if (ops->vidioc_try_fmt_type_private) |
609 | return 0; | 610 | return 0; |
610 | break; | 611 | break; |
611 | } | 612 | } |
612 | return -EINVAL; | 613 | return -EINVAL; |
613 | } | 614 | } |
614 | 615 | ||
615 | static long __video_do_ioctl(struct file *file, | 616 | static long __video_do_ioctl(struct file *file, |
616 | unsigned int cmd, void *arg) | 617 | unsigned int cmd, void *arg) |
617 | { | 618 | { |
618 | struct video_device *vfd = video_devdata(file); | 619 | struct video_device *vfd = video_devdata(file); |
619 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; | 620 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; |
620 | void *fh = file->private_data; | 621 | void *fh = file->private_data; |
621 | long ret = -EINVAL; | 622 | long ret = -EINVAL; |
622 | 623 | ||
623 | if ((vfd->debug & V4L2_DEBUG_IOCTL) && | 624 | if ((vfd->debug & V4L2_DEBUG_IOCTL) && |
624 | !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { | 625 | !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { |
625 | v4l_print_ioctl(vfd->name, cmd); | 626 | v4l_print_ioctl(vfd->name, cmd); |
626 | printk(KERN_CONT "\n"); | 627 | printk(KERN_CONT "\n"); |
627 | } | 628 | } |
628 | 629 | ||
629 | if (ops == NULL) { | 630 | if (ops == NULL) { |
630 | printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", | 631 | printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", |
631 | vfd->name); | 632 | vfd->name); |
632 | return -EINVAL; | 633 | return -EINVAL; |
633 | } | 634 | } |
634 | 635 | ||
635 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 636 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
636 | /*********************************************************** | 637 | /*********************************************************** |
637 | Handles calls to the obsoleted V4L1 API | 638 | Handles calls to the obsoleted V4L1 API |
638 | Due to the nature of VIDIOCGMBUF, each driver that supports | 639 | Due to the nature of VIDIOCGMBUF, each driver that supports |
639 | V4L1 should implement its own handler for this ioctl. | 640 | V4L1 should implement its own handler for this ioctl. |
640 | ***********************************************************/ | 641 | ***********************************************************/ |
641 | 642 | ||
642 | /* --- streaming capture ------------------------------------- */ | 643 | /* --- streaming capture ------------------------------------- */ |
643 | if (cmd == VIDIOCGMBUF) { | 644 | if (cmd == VIDIOCGMBUF) { |
644 | struct video_mbuf *p = arg; | 645 | struct video_mbuf *p = arg; |
645 | 646 | ||
646 | if (!ops->vidiocgmbuf) | 647 | if (!ops->vidiocgmbuf) |
647 | return ret; | 648 | return ret; |
648 | ret = ops->vidiocgmbuf(file, fh, p); | 649 | ret = ops->vidiocgmbuf(file, fh, p); |
649 | if (!ret) | 650 | if (!ret) |
650 | dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n", | 651 | dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n", |
651 | p->size, p->frames, | 652 | p->size, p->frames, |
652 | (unsigned long)p->offsets); | 653 | (unsigned long)p->offsets); |
653 | return ret; | 654 | return ret; |
654 | } | 655 | } |
655 | 656 | ||
656 | /******************************************************** | 657 | /******************************************************** |
657 | All other V4L1 calls are handled by v4l1_compat module. | 658 | All other V4L1 calls are handled by v4l1_compat module. |
658 | Those calls will be translated into V4L2 calls, and | 659 | Those calls will be translated into V4L2 calls, and |
659 | __video_do_ioctl will be called again, with one or more | 660 | __video_do_ioctl will be called again, with one or more |
660 | V4L2 ioctls. | 661 | V4L2 ioctls. |
661 | ********************************************************/ | 662 | ********************************************************/ |
662 | if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) | 663 | if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) |
663 | return v4l_compat_translate_ioctl(file, cmd, arg, | 664 | return v4l_compat_translate_ioctl(file, cmd, arg, |
664 | __video_do_ioctl); | 665 | __video_do_ioctl); |
665 | #endif | 666 | #endif |
666 | 667 | ||
667 | switch (cmd) { | 668 | switch (cmd) { |
668 | /* --- capabilities ------------------------------------------ */ | 669 | /* --- capabilities ------------------------------------------ */ |
669 | case VIDIOC_QUERYCAP: | 670 | case VIDIOC_QUERYCAP: |
670 | { | 671 | { |
671 | struct v4l2_capability *cap = (struct v4l2_capability *)arg; | 672 | struct v4l2_capability *cap = (struct v4l2_capability *)arg; |
672 | 673 | ||
673 | if (!ops->vidioc_querycap) | 674 | if (!ops->vidioc_querycap) |
674 | break; | 675 | break; |
675 | 676 | ||
676 | ret = ops->vidioc_querycap(file, fh, cap); | 677 | ret = ops->vidioc_querycap(file, fh, cap); |
677 | if (!ret) | 678 | if (!ret) |
678 | dbgarg(cmd, "driver=%s, card=%s, bus=%s, " | 679 | dbgarg(cmd, "driver=%s, card=%s, bus=%s, " |
679 | "version=0x%08x, " | 680 | "version=0x%08x, " |
680 | "capabilities=0x%08x\n", | 681 | "capabilities=0x%08x\n", |
681 | cap->driver, cap->card, cap->bus_info, | 682 | cap->driver, cap->card, cap->bus_info, |
682 | cap->version, | 683 | cap->version, |
683 | cap->capabilities); | 684 | cap->capabilities); |
684 | break; | 685 | break; |
685 | } | 686 | } |
686 | 687 | ||
687 | /* --- priority ------------------------------------------ */ | 688 | /* --- priority ------------------------------------------ */ |
688 | case VIDIOC_G_PRIORITY: | 689 | case VIDIOC_G_PRIORITY: |
689 | { | 690 | { |
690 | enum v4l2_priority *p = arg; | 691 | enum v4l2_priority *p = arg; |
691 | 692 | ||
692 | if (!ops->vidioc_g_priority) | 693 | if (!ops->vidioc_g_priority) |
693 | break; | 694 | break; |
694 | ret = ops->vidioc_g_priority(file, fh, p); | 695 | ret = ops->vidioc_g_priority(file, fh, p); |
695 | if (!ret) | 696 | if (!ret) |
696 | dbgarg(cmd, "priority is %d\n", *p); | 697 | dbgarg(cmd, "priority is %d\n", *p); |
697 | break; | 698 | break; |
698 | } | 699 | } |
699 | case VIDIOC_S_PRIORITY: | 700 | case VIDIOC_S_PRIORITY: |
700 | { | 701 | { |
701 | enum v4l2_priority *p = arg; | 702 | enum v4l2_priority *p = arg; |
702 | 703 | ||
703 | if (!ops->vidioc_s_priority) | 704 | if (!ops->vidioc_s_priority) |
704 | break; | 705 | break; |
705 | dbgarg(cmd, "setting priority to %d\n", *p); | 706 | dbgarg(cmd, "setting priority to %d\n", *p); |
706 | ret = ops->vidioc_s_priority(file, fh, *p); | 707 | ret = ops->vidioc_s_priority(file, fh, *p); |
707 | break; | 708 | break; |
708 | } | 709 | } |
709 | 710 | ||
710 | /* --- capture ioctls ---------------------------------------- */ | 711 | /* --- capture ioctls ---------------------------------------- */ |
711 | case VIDIOC_ENUM_FMT: | 712 | case VIDIOC_ENUM_FMT: |
712 | { | 713 | { |
713 | struct v4l2_fmtdesc *f = arg; | 714 | struct v4l2_fmtdesc *f = arg; |
714 | 715 | ||
715 | switch (f->type) { | 716 | switch (f->type) { |
716 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 717 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
717 | if (ops->vidioc_enum_fmt_vid_cap) | 718 | if (ops->vidioc_enum_fmt_vid_cap) |
718 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); | 719 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); |
719 | break; | 720 | break; |
720 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 721 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
721 | if (ops->vidioc_enum_fmt_vid_overlay) | 722 | if (ops->vidioc_enum_fmt_vid_overlay) |
722 | ret = ops->vidioc_enum_fmt_vid_overlay(file, | 723 | ret = ops->vidioc_enum_fmt_vid_overlay(file, |
723 | fh, f); | 724 | fh, f); |
724 | break; | 725 | break; |
725 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 726 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
726 | if (ops->vidioc_enum_fmt_vid_out) | 727 | if (ops->vidioc_enum_fmt_vid_out) |
727 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); | 728 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); |
728 | break; | 729 | break; |
729 | case V4L2_BUF_TYPE_PRIVATE: | 730 | case V4L2_BUF_TYPE_PRIVATE: |
730 | if (ops->vidioc_enum_fmt_type_private) | 731 | if (ops->vidioc_enum_fmt_type_private) |
731 | ret = ops->vidioc_enum_fmt_type_private(file, | 732 | ret = ops->vidioc_enum_fmt_type_private(file, |
732 | fh, f); | 733 | fh, f); |
733 | break; | 734 | break; |
734 | default: | 735 | default: |
735 | break; | 736 | break; |
736 | } | 737 | } |
737 | if (!ret) | 738 | if (!ret) |
738 | dbgarg(cmd, "index=%d, type=%d, flags=%d, " | 739 | dbgarg(cmd, "index=%d, type=%d, flags=%d, " |
739 | "pixelformat=%c%c%c%c, description='%s'\n", | 740 | "pixelformat=%c%c%c%c, description='%s'\n", |
740 | f->index, f->type, f->flags, | 741 | f->index, f->type, f->flags, |
741 | (f->pixelformat & 0xff), | 742 | (f->pixelformat & 0xff), |
742 | (f->pixelformat >> 8) & 0xff, | 743 | (f->pixelformat >> 8) & 0xff, |
743 | (f->pixelformat >> 16) & 0xff, | 744 | (f->pixelformat >> 16) & 0xff, |
744 | (f->pixelformat >> 24) & 0xff, | 745 | (f->pixelformat >> 24) & 0xff, |
745 | f->description); | 746 | f->description); |
746 | break; | 747 | break; |
747 | } | 748 | } |
748 | case VIDIOC_G_FMT: | 749 | case VIDIOC_G_FMT: |
749 | { | 750 | { |
750 | struct v4l2_format *f = (struct v4l2_format *)arg; | 751 | struct v4l2_format *f = (struct v4l2_format *)arg; |
751 | 752 | ||
752 | /* FIXME: Should be one dump per type */ | 753 | /* FIXME: Should be one dump per type */ |
753 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); | 754 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); |
754 | 755 | ||
755 | switch (f->type) { | 756 | switch (f->type) { |
756 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 757 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
757 | if (ops->vidioc_g_fmt_vid_cap) | 758 | if (ops->vidioc_g_fmt_vid_cap) |
758 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); | 759 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); |
759 | if (!ret) | 760 | if (!ret) |
760 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 761 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
761 | break; | 762 | break; |
762 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 763 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
763 | if (ops->vidioc_g_fmt_vid_overlay) | 764 | if (ops->vidioc_g_fmt_vid_overlay) |
764 | ret = ops->vidioc_g_fmt_vid_overlay(file, | 765 | ret = ops->vidioc_g_fmt_vid_overlay(file, |
765 | fh, f); | 766 | fh, f); |
766 | break; | 767 | break; |
767 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 768 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
768 | if (ops->vidioc_g_fmt_vid_out) | 769 | if (ops->vidioc_g_fmt_vid_out) |
769 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); | 770 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); |
770 | if (!ret) | 771 | if (!ret) |
771 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 772 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
772 | break; | 773 | break; |
773 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 774 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
774 | if (ops->vidioc_g_fmt_vid_out_overlay) | 775 | if (ops->vidioc_g_fmt_vid_out_overlay) |
775 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, | 776 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, |
776 | fh, f); | 777 | fh, f); |
777 | break; | 778 | break; |
778 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 779 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
779 | if (ops->vidioc_g_fmt_vbi_cap) | 780 | if (ops->vidioc_g_fmt_vbi_cap) |
780 | ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); | 781 | ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); |
781 | break; | 782 | break; |
782 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 783 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
783 | if (ops->vidioc_g_fmt_vbi_out) | 784 | if (ops->vidioc_g_fmt_vbi_out) |
784 | ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); | 785 | ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); |
785 | break; | 786 | break; |
786 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 787 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
787 | if (ops->vidioc_g_fmt_sliced_vbi_cap) | 788 | if (ops->vidioc_g_fmt_sliced_vbi_cap) |
788 | ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, | 789 | ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, |
789 | fh, f); | 790 | fh, f); |
790 | break; | 791 | break; |
791 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | 792 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: |
792 | if (ops->vidioc_g_fmt_sliced_vbi_out) | 793 | if (ops->vidioc_g_fmt_sliced_vbi_out) |
793 | ret = ops->vidioc_g_fmt_sliced_vbi_out(file, | 794 | ret = ops->vidioc_g_fmt_sliced_vbi_out(file, |
794 | fh, f); | 795 | fh, f); |
795 | break; | 796 | break; |
796 | case V4L2_BUF_TYPE_PRIVATE: | 797 | case V4L2_BUF_TYPE_PRIVATE: |
797 | if (ops->vidioc_g_fmt_type_private) | 798 | if (ops->vidioc_g_fmt_type_private) |
798 | ret = ops->vidioc_g_fmt_type_private(file, | 799 | ret = ops->vidioc_g_fmt_type_private(file, |
799 | fh, f); | 800 | fh, f); |
800 | break; | 801 | break; |
801 | } | 802 | } |
802 | 803 | ||
803 | break; | 804 | break; |
804 | } | 805 | } |
805 | case VIDIOC_S_FMT: | 806 | case VIDIOC_S_FMT: |
806 | { | 807 | { |
807 | struct v4l2_format *f = (struct v4l2_format *)arg; | 808 | struct v4l2_format *f = (struct v4l2_format *)arg; |
808 | 809 | ||
809 | /* FIXME: Should be one dump per type */ | 810 | /* FIXME: Should be one dump per type */ |
810 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); | 811 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); |
811 | 812 | ||
812 | switch (f->type) { | 813 | switch (f->type) { |
813 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 814 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
814 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 815 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
815 | if (ops->vidioc_s_fmt_vid_cap) | 816 | if (ops->vidioc_s_fmt_vid_cap) |
816 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); | 817 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); |
817 | break; | 818 | break; |
818 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 819 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
819 | if (ops->vidioc_s_fmt_vid_overlay) | 820 | if (ops->vidioc_s_fmt_vid_overlay) |
820 | ret = ops->vidioc_s_fmt_vid_overlay(file, | 821 | ret = ops->vidioc_s_fmt_vid_overlay(file, |
821 | fh, f); | 822 | fh, f); |
822 | break; | 823 | break; |
823 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 824 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
824 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 825 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
825 | if (ops->vidioc_s_fmt_vid_out) | 826 | if (ops->vidioc_s_fmt_vid_out) |
826 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); | 827 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); |
827 | break; | 828 | break; |
828 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 829 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
829 | if (ops->vidioc_s_fmt_vid_out_overlay) | 830 | if (ops->vidioc_s_fmt_vid_out_overlay) |
830 | ret = ops->vidioc_s_fmt_vid_out_overlay(file, | 831 | ret = ops->vidioc_s_fmt_vid_out_overlay(file, |
831 | fh, f); | 832 | fh, f); |
832 | break; | 833 | break; |
833 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 834 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
834 | if (ops->vidioc_s_fmt_vbi_cap) | 835 | if (ops->vidioc_s_fmt_vbi_cap) |
835 | ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); | 836 | ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); |
836 | break; | 837 | break; |
837 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 838 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
838 | if (ops->vidioc_s_fmt_vbi_out) | 839 | if (ops->vidioc_s_fmt_vbi_out) |
839 | ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); | 840 | ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); |
840 | break; | 841 | break; |
841 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 842 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
842 | if (ops->vidioc_s_fmt_sliced_vbi_cap) | 843 | if (ops->vidioc_s_fmt_sliced_vbi_cap) |
843 | ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, | 844 | ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, |
844 | fh, f); | 845 | fh, f); |
845 | break; | 846 | break; |
846 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | 847 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: |
847 | if (ops->vidioc_s_fmt_sliced_vbi_out) | 848 | if (ops->vidioc_s_fmt_sliced_vbi_out) |
848 | ret = ops->vidioc_s_fmt_sliced_vbi_out(file, | 849 | ret = ops->vidioc_s_fmt_sliced_vbi_out(file, |
849 | fh, f); | 850 | fh, f); |
850 | break; | 851 | break; |
851 | case V4L2_BUF_TYPE_PRIVATE: | 852 | case V4L2_BUF_TYPE_PRIVATE: |
852 | if (ops->vidioc_s_fmt_type_private) | 853 | if (ops->vidioc_s_fmt_type_private) |
853 | ret = ops->vidioc_s_fmt_type_private(file, | 854 | ret = ops->vidioc_s_fmt_type_private(file, |
854 | fh, f); | 855 | fh, f); |
855 | break; | 856 | break; |
856 | } | 857 | } |
857 | break; | 858 | break; |
858 | } | 859 | } |
859 | case VIDIOC_TRY_FMT: | 860 | case VIDIOC_TRY_FMT: |
860 | { | 861 | { |
861 | struct v4l2_format *f = (struct v4l2_format *)arg; | 862 | struct v4l2_format *f = (struct v4l2_format *)arg; |
862 | 863 | ||
863 | /* FIXME: Should be one dump per type */ | 864 | /* FIXME: Should be one dump per type */ |
864 | dbgarg(cmd, "type=%s\n", prt_names(f->type, | 865 | dbgarg(cmd, "type=%s\n", prt_names(f->type, |
865 | v4l2_type_names)); | 866 | v4l2_type_names)); |
866 | switch (f->type) { | 867 | switch (f->type) { |
867 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 868 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
868 | if (ops->vidioc_try_fmt_vid_cap) | 869 | if (ops->vidioc_try_fmt_vid_cap) |
869 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); | 870 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); |
870 | if (!ret) | 871 | if (!ret) |
871 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 872 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
872 | break; | 873 | break; |
873 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 874 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
874 | if (ops->vidioc_try_fmt_vid_overlay) | 875 | if (ops->vidioc_try_fmt_vid_overlay) |
875 | ret = ops->vidioc_try_fmt_vid_overlay(file, | 876 | ret = ops->vidioc_try_fmt_vid_overlay(file, |
876 | fh, f); | 877 | fh, f); |
877 | break; | 878 | break; |
878 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 879 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
879 | if (ops->vidioc_try_fmt_vid_out) | 880 | if (ops->vidioc_try_fmt_vid_out) |
880 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); | 881 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); |
881 | if (!ret) | 882 | if (!ret) |
882 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 883 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
883 | break; | 884 | break; |
884 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 885 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
885 | if (ops->vidioc_try_fmt_vid_out_overlay) | 886 | if (ops->vidioc_try_fmt_vid_out_overlay) |
886 | ret = ops->vidioc_try_fmt_vid_out_overlay(file, | 887 | ret = ops->vidioc_try_fmt_vid_out_overlay(file, |
887 | fh, f); | 888 | fh, f); |
888 | break; | 889 | break; |
889 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 890 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
890 | if (ops->vidioc_try_fmt_vbi_cap) | 891 | if (ops->vidioc_try_fmt_vbi_cap) |
891 | ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); | 892 | ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); |
892 | break; | 893 | break; |
893 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 894 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
894 | if (ops->vidioc_try_fmt_vbi_out) | 895 | if (ops->vidioc_try_fmt_vbi_out) |
895 | ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); | 896 | ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); |
896 | break; | 897 | break; |
897 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 898 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
898 | if (ops->vidioc_try_fmt_sliced_vbi_cap) | 899 | if (ops->vidioc_try_fmt_sliced_vbi_cap) |
899 | ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, | 900 | ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, |
900 | fh, f); | 901 | fh, f); |
901 | break; | 902 | break; |
902 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | 903 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: |
903 | if (ops->vidioc_try_fmt_sliced_vbi_out) | 904 | if (ops->vidioc_try_fmt_sliced_vbi_out) |
904 | ret = ops->vidioc_try_fmt_sliced_vbi_out(file, | 905 | ret = ops->vidioc_try_fmt_sliced_vbi_out(file, |
905 | fh, f); | 906 | fh, f); |
906 | break; | 907 | break; |
907 | case V4L2_BUF_TYPE_PRIVATE: | 908 | case V4L2_BUF_TYPE_PRIVATE: |
908 | if (ops->vidioc_try_fmt_type_private) | 909 | if (ops->vidioc_try_fmt_type_private) |
909 | ret = ops->vidioc_try_fmt_type_private(file, | 910 | ret = ops->vidioc_try_fmt_type_private(file, |
910 | fh, f); | 911 | fh, f); |
911 | break; | 912 | break; |
912 | } | 913 | } |
913 | 914 | ||
914 | break; | 915 | break; |
915 | } | 916 | } |
916 | /* FIXME: Those buf reqs could be handled here, | 917 | /* FIXME: Those buf reqs could be handled here, |
917 | with some changes on videobuf to allow its header to be included at | 918 | with some changes on videobuf to allow its header to be included at |
918 | videodev2.h or being merged at videodev2. | 919 | videodev2.h or being merged at videodev2. |
919 | */ | 920 | */ |
920 | case VIDIOC_REQBUFS: | 921 | case VIDIOC_REQBUFS: |
921 | { | 922 | { |
922 | struct v4l2_requestbuffers *p = arg; | 923 | struct v4l2_requestbuffers *p = arg; |
923 | 924 | ||
924 | if (!ops->vidioc_reqbufs) | 925 | if (!ops->vidioc_reqbufs) |
925 | break; | 926 | break; |
926 | ret = check_fmt(ops, p->type); | 927 | ret = check_fmt(ops, p->type); |
927 | if (ret) | 928 | if (ret) |
928 | break; | 929 | break; |
929 | 930 | ||
930 | ret = ops->vidioc_reqbufs(file, fh, p); | 931 | ret = ops->vidioc_reqbufs(file, fh, p); |
931 | dbgarg(cmd, "count=%d, type=%s, memory=%s\n", | 932 | dbgarg(cmd, "count=%d, type=%s, memory=%s\n", |
932 | p->count, | 933 | p->count, |
933 | prt_names(p->type, v4l2_type_names), | 934 | prt_names(p->type, v4l2_type_names), |
934 | prt_names(p->memory, v4l2_memory_names)); | 935 | prt_names(p->memory, v4l2_memory_names)); |
935 | break; | 936 | break; |
936 | } | 937 | } |
937 | case VIDIOC_QUERYBUF: | 938 | case VIDIOC_QUERYBUF: |
938 | { | 939 | { |
939 | struct v4l2_buffer *p = arg; | 940 | struct v4l2_buffer *p = arg; |
940 | 941 | ||
941 | if (!ops->vidioc_querybuf) | 942 | if (!ops->vidioc_querybuf) |
942 | break; | 943 | break; |
943 | ret = check_fmt(ops, p->type); | 944 | ret = check_fmt(ops, p->type); |
944 | if (ret) | 945 | if (ret) |
945 | break; | 946 | break; |
946 | 947 | ||
947 | ret = ops->vidioc_querybuf(file, fh, p); | 948 | ret = ops->vidioc_querybuf(file, fh, p); |
948 | if (!ret) | 949 | if (!ret) |
949 | dbgbuf(cmd, vfd, p); | 950 | dbgbuf(cmd, vfd, p); |
950 | break; | 951 | break; |
951 | } | 952 | } |
952 | case VIDIOC_QBUF: | 953 | case VIDIOC_QBUF: |
953 | { | 954 | { |
954 | struct v4l2_buffer *p = arg; | 955 | struct v4l2_buffer *p = arg; |
955 | 956 | ||
956 | if (!ops->vidioc_qbuf) | 957 | if (!ops->vidioc_qbuf) |
957 | break; | 958 | break; |
958 | ret = check_fmt(ops, p->type); | 959 | ret = check_fmt(ops, p->type); |
959 | if (ret) | 960 | if (ret) |
960 | break; | 961 | break; |
961 | 962 | ||
962 | ret = ops->vidioc_qbuf(file, fh, p); | 963 | ret = ops->vidioc_qbuf(file, fh, p); |
963 | if (!ret) | 964 | if (!ret) |
964 | dbgbuf(cmd, vfd, p); | 965 | dbgbuf(cmd, vfd, p); |
965 | break; | 966 | break; |
966 | } | 967 | } |
967 | case VIDIOC_DQBUF: | 968 | case VIDIOC_DQBUF: |
968 | { | 969 | { |
969 | struct v4l2_buffer *p = arg; | 970 | struct v4l2_buffer *p = arg; |
970 | 971 | ||
971 | if (!ops->vidioc_dqbuf) | 972 | if (!ops->vidioc_dqbuf) |
972 | break; | 973 | break; |
973 | ret = check_fmt(ops, p->type); | 974 | ret = check_fmt(ops, p->type); |
974 | if (ret) | 975 | if (ret) |
975 | break; | 976 | break; |
976 | 977 | ||
977 | ret = ops->vidioc_dqbuf(file, fh, p); | 978 | ret = ops->vidioc_dqbuf(file, fh, p); |
978 | if (!ret) | 979 | if (!ret) |
979 | dbgbuf(cmd, vfd, p); | 980 | dbgbuf(cmd, vfd, p); |
980 | break; | 981 | break; |
981 | } | 982 | } |
982 | case VIDIOC_OVERLAY: | 983 | case VIDIOC_OVERLAY: |
983 | { | 984 | { |
984 | int *i = arg; | 985 | int *i = arg; |
985 | 986 | ||
986 | if (!ops->vidioc_overlay) | 987 | if (!ops->vidioc_overlay) |
987 | break; | 988 | break; |
988 | dbgarg(cmd, "value=%d\n", *i); | 989 | dbgarg(cmd, "value=%d\n", *i); |
989 | ret = ops->vidioc_overlay(file, fh, *i); | 990 | ret = ops->vidioc_overlay(file, fh, *i); |
990 | break; | 991 | break; |
991 | } | 992 | } |
992 | case VIDIOC_G_FBUF: | 993 | case VIDIOC_G_FBUF: |
993 | { | 994 | { |
994 | struct v4l2_framebuffer *p = arg; | 995 | struct v4l2_framebuffer *p = arg; |
995 | 996 | ||
996 | if (!ops->vidioc_g_fbuf) | 997 | if (!ops->vidioc_g_fbuf) |
997 | break; | 998 | break; |
998 | ret = ops->vidioc_g_fbuf(file, fh, arg); | 999 | ret = ops->vidioc_g_fbuf(file, fh, arg); |
999 | if (!ret) { | 1000 | if (!ret) { |
1000 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", | 1001 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", |
1001 | p->capability, p->flags, | 1002 | p->capability, p->flags, |
1002 | (unsigned long)p->base); | 1003 | (unsigned long)p->base); |
1003 | v4l_print_pix_fmt(vfd, &p->fmt); | 1004 | v4l_print_pix_fmt(vfd, &p->fmt); |
1004 | } | 1005 | } |
1005 | break; | 1006 | break; |
1006 | } | 1007 | } |
1007 | case VIDIOC_S_FBUF: | 1008 | case VIDIOC_S_FBUF: |
1008 | { | 1009 | { |
1009 | struct v4l2_framebuffer *p = arg; | 1010 | struct v4l2_framebuffer *p = arg; |
1010 | 1011 | ||
1011 | if (!ops->vidioc_s_fbuf) | 1012 | if (!ops->vidioc_s_fbuf) |
1012 | break; | 1013 | break; |
1013 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", | 1014 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", |
1014 | p->capability, p->flags, (unsigned long)p->base); | 1015 | p->capability, p->flags, (unsigned long)p->base); |
1015 | v4l_print_pix_fmt(vfd, &p->fmt); | 1016 | v4l_print_pix_fmt(vfd, &p->fmt); |
1016 | ret = ops->vidioc_s_fbuf(file, fh, arg); | 1017 | ret = ops->vidioc_s_fbuf(file, fh, arg); |
1017 | break; | 1018 | break; |
1018 | } | 1019 | } |
1019 | case VIDIOC_STREAMON: | 1020 | case VIDIOC_STREAMON: |
1020 | { | 1021 | { |
1021 | enum v4l2_buf_type i = *(int *)arg; | 1022 | enum v4l2_buf_type i = *(int *)arg; |
1022 | 1023 | ||
1023 | if (!ops->vidioc_streamon) | 1024 | if (!ops->vidioc_streamon) |
1024 | break; | 1025 | break; |
1025 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); | 1026 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); |
1026 | ret = ops->vidioc_streamon(file, fh, i); | 1027 | ret = ops->vidioc_streamon(file, fh, i); |
1027 | break; | 1028 | break; |
1028 | } | 1029 | } |
1029 | case VIDIOC_STREAMOFF: | 1030 | case VIDIOC_STREAMOFF: |
1030 | { | 1031 | { |
1031 | enum v4l2_buf_type i = *(int *)arg; | 1032 | enum v4l2_buf_type i = *(int *)arg; |
1032 | 1033 | ||
1033 | if (!ops->vidioc_streamoff) | 1034 | if (!ops->vidioc_streamoff) |
1034 | break; | 1035 | break; |
1035 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); | 1036 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); |
1036 | ret = ops->vidioc_streamoff(file, fh, i); | 1037 | ret = ops->vidioc_streamoff(file, fh, i); |
1037 | break; | 1038 | break; |
1038 | } | 1039 | } |
1039 | /* ---------- tv norms ---------- */ | 1040 | /* ---------- tv norms ---------- */ |
1040 | case VIDIOC_ENUMSTD: | 1041 | case VIDIOC_ENUMSTD: |
1041 | { | 1042 | { |
1042 | struct v4l2_standard *p = arg; | 1043 | struct v4l2_standard *p = arg; |
1043 | v4l2_std_id id = vfd->tvnorms, curr_id = 0; | 1044 | v4l2_std_id id = vfd->tvnorms, curr_id = 0; |
1044 | unsigned int index = p->index, i, j = 0; | 1045 | unsigned int index = p->index, i, j = 0; |
1045 | const char *descr = ""; | 1046 | const char *descr = ""; |
1046 | 1047 | ||
1047 | /* Return norm array in a canonical way */ | 1048 | /* Return norm array in a canonical way */ |
1048 | for (i = 0; i <= index && id; i++) { | 1049 | for (i = 0; i <= index && id; i++) { |
1049 | /* last std value in the standards array is 0, so this | 1050 | /* last std value in the standards array is 0, so this |
1050 | while always ends there since (id & 0) == 0. */ | 1051 | while always ends there since (id & 0) == 0. */ |
1051 | while ((id & standards[j].std) != standards[j].std) | 1052 | while ((id & standards[j].std) != standards[j].std) |
1052 | j++; | 1053 | j++; |
1053 | curr_id = standards[j].std; | 1054 | curr_id = standards[j].std; |
1054 | descr = standards[j].descr; | 1055 | descr = standards[j].descr; |
1055 | j++; | 1056 | j++; |
1056 | if (curr_id == 0) | 1057 | if (curr_id == 0) |
1057 | break; | 1058 | break; |
1058 | if (curr_id != V4L2_STD_PAL && | 1059 | if (curr_id != V4L2_STD_PAL && |
1059 | curr_id != V4L2_STD_SECAM && | 1060 | curr_id != V4L2_STD_SECAM && |
1060 | curr_id != V4L2_STD_NTSC) | 1061 | curr_id != V4L2_STD_NTSC) |
1061 | id &= ~curr_id; | 1062 | id &= ~curr_id; |
1062 | } | 1063 | } |
1063 | if (i <= index) | 1064 | if (i <= index) |
1064 | return -EINVAL; | 1065 | return -EINVAL; |
1065 | 1066 | ||
1066 | v4l2_video_std_construct(p, curr_id, descr); | 1067 | v4l2_video_std_construct(p, curr_id, descr); |
1067 | 1068 | ||
1068 | dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " | 1069 | dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " |
1069 | "framelines=%d\n", p->index, | 1070 | "framelines=%d\n", p->index, |
1070 | (unsigned long long)p->id, p->name, | 1071 | (unsigned long long)p->id, p->name, |
1071 | p->frameperiod.numerator, | 1072 | p->frameperiod.numerator, |
1072 | p->frameperiod.denominator, | 1073 | p->frameperiod.denominator, |
1073 | p->framelines); | 1074 | p->framelines); |
1074 | 1075 | ||
1075 | ret = 0; | 1076 | ret = 0; |
1076 | break; | 1077 | break; |
1077 | } | 1078 | } |
1078 | case VIDIOC_G_STD: | 1079 | case VIDIOC_G_STD: |
1079 | { | 1080 | { |
1080 | v4l2_std_id *id = arg; | 1081 | v4l2_std_id *id = arg; |
1081 | 1082 | ||
1082 | ret = 0; | 1083 | ret = 0; |
1083 | /* Calls the specific handler */ | 1084 | /* Calls the specific handler */ |
1084 | if (ops->vidioc_g_std) | 1085 | if (ops->vidioc_g_std) |
1085 | ret = ops->vidioc_g_std(file, fh, id); | 1086 | ret = ops->vidioc_g_std(file, fh, id); |
1086 | else | 1087 | else |
1087 | *id = vfd->current_norm; | 1088 | *id = vfd->current_norm; |
1088 | 1089 | ||
1089 | if (!ret) | 1090 | if (!ret) |
1090 | dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); | 1091 | dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); |
1091 | break; | 1092 | break; |
1092 | } | 1093 | } |
1093 | case VIDIOC_S_STD: | 1094 | case VIDIOC_S_STD: |
1094 | { | 1095 | { |
1095 | v4l2_std_id *id = arg, norm; | 1096 | v4l2_std_id *id = arg, norm; |
1096 | 1097 | ||
1097 | dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); | 1098 | dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); |
1098 | 1099 | ||
1099 | norm = (*id) & vfd->tvnorms; | 1100 | norm = (*id) & vfd->tvnorms; |
1100 | if (vfd->tvnorms && !norm) /* Check if std is supported */ | 1101 | if (vfd->tvnorms && !norm) /* Check if std is supported */ |
1101 | break; | 1102 | break; |
1102 | 1103 | ||
1103 | /* Calls the specific handler */ | 1104 | /* Calls the specific handler */ |
1104 | if (ops->vidioc_s_std) | 1105 | if (ops->vidioc_s_std) |
1105 | ret = ops->vidioc_s_std(file, fh, &norm); | 1106 | ret = ops->vidioc_s_std(file, fh, &norm); |
1106 | else | 1107 | else |
1107 | ret = -EINVAL; | 1108 | ret = -EINVAL; |
1108 | 1109 | ||
1109 | /* Updates standard information */ | 1110 | /* Updates standard information */ |
1110 | if (ret >= 0) | 1111 | if (ret >= 0) |
1111 | vfd->current_norm = norm; | 1112 | vfd->current_norm = norm; |
1112 | break; | 1113 | break; |
1113 | } | 1114 | } |
1114 | case VIDIOC_QUERYSTD: | 1115 | case VIDIOC_QUERYSTD: |
1115 | { | 1116 | { |
1116 | v4l2_std_id *p = arg; | 1117 | v4l2_std_id *p = arg; |
1117 | 1118 | ||
1118 | if (!ops->vidioc_querystd) | 1119 | if (!ops->vidioc_querystd) |
1119 | break; | 1120 | break; |
1120 | ret = ops->vidioc_querystd(file, fh, arg); | 1121 | ret = ops->vidioc_querystd(file, fh, arg); |
1121 | if (!ret) | 1122 | if (!ret) |
1122 | dbgarg(cmd, "detected std=%08Lx\n", | 1123 | dbgarg(cmd, "detected std=%08Lx\n", |
1123 | (unsigned long long)*p); | 1124 | (unsigned long long)*p); |
1124 | break; | 1125 | break; |
1125 | } | 1126 | } |
1126 | /* ------ input switching ---------- */ | 1127 | /* ------ input switching ---------- */ |
1127 | /* FIXME: Inputs can be handled inside videodev2 */ | 1128 | /* FIXME: Inputs can be handled inside videodev2 */ |
1128 | case VIDIOC_ENUMINPUT: | 1129 | case VIDIOC_ENUMINPUT: |
1129 | { | 1130 | { |
1130 | struct v4l2_input *p = arg; | 1131 | struct v4l2_input *p = arg; |
1131 | 1132 | ||
1132 | if (!ops->vidioc_enum_input) | 1133 | if (!ops->vidioc_enum_input) |
1133 | break; | 1134 | break; |
1134 | 1135 | ||
1135 | ret = ops->vidioc_enum_input(file, fh, p); | 1136 | ret = ops->vidioc_enum_input(file, fh, p); |
1136 | if (!ret) | 1137 | if (!ret) |
1137 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | 1138 | dbgarg(cmd, "index=%d, name=%s, type=%d, " |
1138 | "audioset=%d, " | 1139 | "audioset=%d, " |
1139 | "tuner=%d, std=%08Lx, status=%d\n", | 1140 | "tuner=%d, std=%08Lx, status=%d\n", |
1140 | p->index, p->name, p->type, p->audioset, | 1141 | p->index, p->name, p->type, p->audioset, |
1141 | p->tuner, | 1142 | p->tuner, |
1142 | (unsigned long long)p->std, | 1143 | (unsigned long long)p->std, |
1143 | p->status); | 1144 | p->status); |
1144 | break; | 1145 | break; |
1145 | } | 1146 | } |
1146 | case VIDIOC_G_INPUT: | 1147 | case VIDIOC_G_INPUT: |
1147 | { | 1148 | { |
1148 | unsigned int *i = arg; | 1149 | unsigned int *i = arg; |
1149 | 1150 | ||
1150 | if (!ops->vidioc_g_input) | 1151 | if (!ops->vidioc_g_input) |
1151 | break; | 1152 | break; |
1152 | ret = ops->vidioc_g_input(file, fh, i); | 1153 | ret = ops->vidioc_g_input(file, fh, i); |
1153 | if (!ret) | 1154 | if (!ret) |
1154 | dbgarg(cmd, "value=%d\n", *i); | 1155 | dbgarg(cmd, "value=%d\n", *i); |
1155 | break; | 1156 | break; |
1156 | } | 1157 | } |
1157 | case VIDIOC_S_INPUT: | 1158 | case VIDIOC_S_INPUT: |
1158 | { | 1159 | { |
1159 | unsigned int *i = arg; | 1160 | unsigned int *i = arg; |
1160 | 1161 | ||
1161 | if (!ops->vidioc_s_input) | 1162 | if (!ops->vidioc_s_input) |
1162 | break; | 1163 | break; |
1163 | dbgarg(cmd, "value=%d\n", *i); | 1164 | dbgarg(cmd, "value=%d\n", *i); |
1164 | ret = ops->vidioc_s_input(file, fh, *i); | 1165 | ret = ops->vidioc_s_input(file, fh, *i); |
1165 | break; | 1166 | break; |
1166 | } | 1167 | } |
1167 | 1168 | ||
1168 | /* ------ output switching ---------- */ | 1169 | /* ------ output switching ---------- */ |
1169 | case VIDIOC_ENUMOUTPUT: | 1170 | case VIDIOC_ENUMOUTPUT: |
1170 | { | 1171 | { |
1171 | struct v4l2_output *p = arg; | 1172 | struct v4l2_output *p = arg; |
1172 | 1173 | ||
1173 | if (!ops->vidioc_enum_output) | 1174 | if (!ops->vidioc_enum_output) |
1174 | break; | 1175 | break; |
1175 | 1176 | ||
1176 | ret = ops->vidioc_enum_output(file, fh, p); | 1177 | ret = ops->vidioc_enum_output(file, fh, p); |
1177 | if (!ret) | 1178 | if (!ret) |
1178 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | 1179 | dbgarg(cmd, "index=%d, name=%s, type=%d, " |
1179 | "audioset=0x%x, " | 1180 | "audioset=0x%x, " |
1180 | "modulator=%d, std=0x%08Lx\n", | 1181 | "modulator=%d, std=0x%08Lx\n", |
1181 | p->index, p->name, p->type, p->audioset, | 1182 | p->index, p->name, p->type, p->audioset, |
1182 | p->modulator, (unsigned long long)p->std); | 1183 | p->modulator, (unsigned long long)p->std); |
1183 | break; | 1184 | break; |
1184 | } | 1185 | } |
1185 | case VIDIOC_G_OUTPUT: | 1186 | case VIDIOC_G_OUTPUT: |
1186 | { | 1187 | { |
1187 | unsigned int *i = arg; | 1188 | unsigned int *i = arg; |
1188 | 1189 | ||
1189 | if (!ops->vidioc_g_output) | 1190 | if (!ops->vidioc_g_output) |
1190 | break; | 1191 | break; |
1191 | ret = ops->vidioc_g_output(file, fh, i); | 1192 | ret = ops->vidioc_g_output(file, fh, i); |
1192 | if (!ret) | 1193 | if (!ret) |
1193 | dbgarg(cmd, "value=%d\n", *i); | 1194 | dbgarg(cmd, "value=%d\n", *i); |
1194 | break; | 1195 | break; |
1195 | } | 1196 | } |
1196 | case VIDIOC_S_OUTPUT: | 1197 | case VIDIOC_S_OUTPUT: |
1197 | { | 1198 | { |
1198 | unsigned int *i = arg; | 1199 | unsigned int *i = arg; |
1199 | 1200 | ||
1200 | if (!ops->vidioc_s_output) | 1201 | if (!ops->vidioc_s_output) |
1201 | break; | 1202 | break; |
1202 | dbgarg(cmd, "value=%d\n", *i); | 1203 | dbgarg(cmd, "value=%d\n", *i); |
1203 | ret = ops->vidioc_s_output(file, fh, *i); | 1204 | ret = ops->vidioc_s_output(file, fh, *i); |
1204 | break; | 1205 | break; |
1205 | } | 1206 | } |
1206 | 1207 | ||
1207 | /* --- controls ---------------------------------------------- */ | 1208 | /* --- controls ---------------------------------------------- */ |
1208 | case VIDIOC_QUERYCTRL: | 1209 | case VIDIOC_QUERYCTRL: |
1209 | { | 1210 | { |
1210 | struct v4l2_queryctrl *p = arg; | 1211 | struct v4l2_queryctrl *p = arg; |
1211 | 1212 | ||
1212 | if (!ops->vidioc_queryctrl) | 1213 | if (!ops->vidioc_queryctrl) |
1213 | break; | 1214 | break; |
1214 | ret = ops->vidioc_queryctrl(file, fh, p); | 1215 | ret = ops->vidioc_queryctrl(file, fh, p); |
1215 | if (!ret) | 1216 | if (!ret) |
1216 | dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " | 1217 | dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " |
1217 | "step=%d, default=%d, flags=0x%08x\n", | 1218 | "step=%d, default=%d, flags=0x%08x\n", |
1218 | p->id, p->type, p->name, | 1219 | p->id, p->type, p->name, |
1219 | p->minimum, p->maximum, | 1220 | p->minimum, p->maximum, |
1220 | p->step, p->default_value, p->flags); | 1221 | p->step, p->default_value, p->flags); |
1221 | else | 1222 | else |
1222 | dbgarg(cmd, "id=0x%x\n", p->id); | 1223 | dbgarg(cmd, "id=0x%x\n", p->id); |
1223 | break; | 1224 | break; |
1224 | } | 1225 | } |
1225 | case VIDIOC_G_CTRL: | 1226 | case VIDIOC_G_CTRL: |
1226 | { | 1227 | { |
1227 | struct v4l2_control *p = arg; | 1228 | struct v4l2_control *p = arg; |
1228 | 1229 | ||
1229 | if (ops->vidioc_g_ctrl) | 1230 | if (ops->vidioc_g_ctrl) |
1230 | ret = ops->vidioc_g_ctrl(file, fh, p); | 1231 | ret = ops->vidioc_g_ctrl(file, fh, p); |
1231 | else if (ops->vidioc_g_ext_ctrls) { | 1232 | else if (ops->vidioc_g_ext_ctrls) { |
1232 | struct v4l2_ext_controls ctrls; | 1233 | struct v4l2_ext_controls ctrls; |
1233 | struct v4l2_ext_control ctrl; | 1234 | struct v4l2_ext_control ctrl; |
1234 | 1235 | ||
1235 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); | 1236 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); |
1236 | ctrls.count = 1; | 1237 | ctrls.count = 1; |
1237 | ctrls.controls = &ctrl; | 1238 | ctrls.controls = &ctrl; |
1238 | ctrl.id = p->id; | 1239 | ctrl.id = p->id; |
1239 | ctrl.value = p->value; | 1240 | ctrl.value = p->value; |
1240 | if (check_ext_ctrls(&ctrls, 1)) { | 1241 | if (check_ext_ctrls(&ctrls, 1)) { |
1241 | ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); | 1242 | ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); |
1242 | if (ret == 0) | 1243 | if (ret == 0) |
1243 | p->value = ctrl.value; | 1244 | p->value = ctrl.value; |
1244 | } | 1245 | } |
1245 | } else | 1246 | } else |
1246 | break; | 1247 | break; |
1247 | if (!ret) | 1248 | if (!ret) |
1248 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); | 1249 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); |
1249 | else | 1250 | else |
1250 | dbgarg(cmd, "id=0x%x\n", p->id); | 1251 | dbgarg(cmd, "id=0x%x\n", p->id); |
1251 | break; | 1252 | break; |
1252 | } | 1253 | } |
1253 | case VIDIOC_S_CTRL: | 1254 | case VIDIOC_S_CTRL: |
1254 | { | 1255 | { |
1255 | struct v4l2_control *p = arg; | 1256 | struct v4l2_control *p = arg; |
1256 | struct v4l2_ext_controls ctrls; | 1257 | struct v4l2_ext_controls ctrls; |
1257 | struct v4l2_ext_control ctrl; | 1258 | struct v4l2_ext_control ctrl; |
1258 | 1259 | ||
1259 | if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) | 1260 | if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) |
1260 | break; | 1261 | break; |
1261 | 1262 | ||
1262 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); | 1263 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); |
1263 | 1264 | ||
1264 | if (ops->vidioc_s_ctrl) { | 1265 | if (ops->vidioc_s_ctrl) { |
1265 | ret = ops->vidioc_s_ctrl(file, fh, p); | 1266 | ret = ops->vidioc_s_ctrl(file, fh, p); |
1266 | break; | 1267 | break; |
1267 | } | 1268 | } |
1268 | if (!ops->vidioc_s_ext_ctrls) | 1269 | if (!ops->vidioc_s_ext_ctrls) |
1269 | break; | 1270 | break; |
1270 | 1271 | ||
1271 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); | 1272 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); |
1272 | ctrls.count = 1; | 1273 | ctrls.count = 1; |
1273 | ctrls.controls = &ctrl; | 1274 | ctrls.controls = &ctrl; |
1274 | ctrl.id = p->id; | 1275 | ctrl.id = p->id; |
1275 | ctrl.value = p->value; | 1276 | ctrl.value = p->value; |
1276 | if (check_ext_ctrls(&ctrls, 1)) | 1277 | if (check_ext_ctrls(&ctrls, 1)) |
1277 | ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); | 1278 | ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); |
1278 | break; | 1279 | break; |
1279 | } | 1280 | } |
1280 | case VIDIOC_G_EXT_CTRLS: | 1281 | case VIDIOC_G_EXT_CTRLS: |
1281 | { | 1282 | { |
1282 | struct v4l2_ext_controls *p = arg; | 1283 | struct v4l2_ext_controls *p = arg; |
1283 | 1284 | ||
1284 | p->error_idx = p->count; | 1285 | p->error_idx = p->count; |
1285 | if (!ops->vidioc_g_ext_ctrls) | 1286 | if (!ops->vidioc_g_ext_ctrls) |
1286 | break; | 1287 | break; |
1287 | if (check_ext_ctrls(p, 0)) | 1288 | if (check_ext_ctrls(p, 0)) |
1288 | ret = ops->vidioc_g_ext_ctrls(file, fh, p); | 1289 | ret = ops->vidioc_g_ext_ctrls(file, fh, p); |
1289 | v4l_print_ext_ctrls(cmd, vfd, p, !ret); | 1290 | v4l_print_ext_ctrls(cmd, vfd, p, !ret); |
1290 | break; | 1291 | break; |
1291 | } | 1292 | } |
1292 | case VIDIOC_S_EXT_CTRLS: | 1293 | case VIDIOC_S_EXT_CTRLS: |
1293 | { | 1294 | { |
1294 | struct v4l2_ext_controls *p = arg; | 1295 | struct v4l2_ext_controls *p = arg; |
1295 | 1296 | ||
1296 | p->error_idx = p->count; | 1297 | p->error_idx = p->count; |
1297 | if (!ops->vidioc_s_ext_ctrls) | 1298 | if (!ops->vidioc_s_ext_ctrls) |
1298 | break; | 1299 | break; |
1299 | v4l_print_ext_ctrls(cmd, vfd, p, 1); | 1300 | v4l_print_ext_ctrls(cmd, vfd, p, 1); |
1300 | if (check_ext_ctrls(p, 0)) | 1301 | if (check_ext_ctrls(p, 0)) |
1301 | ret = ops->vidioc_s_ext_ctrls(file, fh, p); | 1302 | ret = ops->vidioc_s_ext_ctrls(file, fh, p); |
1302 | break; | 1303 | break; |
1303 | } | 1304 | } |
1304 | case VIDIOC_TRY_EXT_CTRLS: | 1305 | case VIDIOC_TRY_EXT_CTRLS: |
1305 | { | 1306 | { |
1306 | struct v4l2_ext_controls *p = arg; | 1307 | struct v4l2_ext_controls *p = arg; |
1307 | 1308 | ||
1308 | p->error_idx = p->count; | 1309 | p->error_idx = p->count; |
1309 | if (!ops->vidioc_try_ext_ctrls) | 1310 | if (!ops->vidioc_try_ext_ctrls) |
1310 | break; | 1311 | break; |
1311 | v4l_print_ext_ctrls(cmd, vfd, p, 1); | 1312 | v4l_print_ext_ctrls(cmd, vfd, p, 1); |
1312 | if (check_ext_ctrls(p, 0)) | 1313 | if (check_ext_ctrls(p, 0)) |
1313 | ret = ops->vidioc_try_ext_ctrls(file, fh, p); | 1314 | ret = ops->vidioc_try_ext_ctrls(file, fh, p); |
1314 | break; | 1315 | break; |
1315 | } | 1316 | } |
1316 | case VIDIOC_QUERYMENU: | 1317 | case VIDIOC_QUERYMENU: |
1317 | { | 1318 | { |
1318 | struct v4l2_querymenu *p = arg; | 1319 | struct v4l2_querymenu *p = arg; |
1319 | 1320 | ||
1320 | if (!ops->vidioc_querymenu) | 1321 | if (!ops->vidioc_querymenu) |
1321 | break; | 1322 | break; |
1322 | ret = ops->vidioc_querymenu(file, fh, p); | 1323 | ret = ops->vidioc_querymenu(file, fh, p); |
1323 | if (!ret) | 1324 | if (!ret) |
1324 | dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", | 1325 | dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", |
1325 | p->id, p->index, p->name); | 1326 | p->id, p->index, p->name); |
1326 | else | 1327 | else |
1327 | dbgarg(cmd, "id=0x%x, index=%d\n", | 1328 | dbgarg(cmd, "id=0x%x, index=%d\n", |
1328 | p->id, p->index); | 1329 | p->id, p->index); |
1329 | break; | 1330 | break; |
1330 | } | 1331 | } |
1331 | /* --- audio ---------------------------------------------- */ | 1332 | /* --- audio ---------------------------------------------- */ |
1332 | case VIDIOC_ENUMAUDIO: | 1333 | case VIDIOC_ENUMAUDIO: |
1333 | { | 1334 | { |
1334 | struct v4l2_audio *p = arg; | 1335 | struct v4l2_audio *p = arg; |
1335 | 1336 | ||
1336 | if (!ops->vidioc_enumaudio) | 1337 | if (!ops->vidioc_enumaudio) |
1337 | break; | 1338 | break; |
1338 | ret = ops->vidioc_enumaudio(file, fh, p); | 1339 | ret = ops->vidioc_enumaudio(file, fh, p); |
1339 | if (!ret) | 1340 | if (!ret) |
1340 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | 1341 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " |
1341 | "mode=0x%x\n", p->index, p->name, | 1342 | "mode=0x%x\n", p->index, p->name, |
1342 | p->capability, p->mode); | 1343 | p->capability, p->mode); |
1343 | else | 1344 | else |
1344 | dbgarg(cmd, "index=%d\n", p->index); | 1345 | dbgarg(cmd, "index=%d\n", p->index); |
1345 | break; | 1346 | break; |
1346 | } | 1347 | } |
1347 | case VIDIOC_G_AUDIO: | 1348 | case VIDIOC_G_AUDIO: |
1348 | { | 1349 | { |
1349 | struct v4l2_audio *p = arg; | 1350 | struct v4l2_audio *p = arg; |
1350 | 1351 | ||
1351 | if (!ops->vidioc_g_audio) | 1352 | if (!ops->vidioc_g_audio) |
1352 | break; | 1353 | break; |
1353 | 1354 | ||
1354 | ret = ops->vidioc_g_audio(file, fh, p); | 1355 | ret = ops->vidioc_g_audio(file, fh, p); |
1355 | if (!ret) | 1356 | if (!ret) |
1356 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | 1357 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " |
1357 | "mode=0x%x\n", p->index, | 1358 | "mode=0x%x\n", p->index, |
1358 | p->name, p->capability, p->mode); | 1359 | p->name, p->capability, p->mode); |
1359 | else | 1360 | else |
1360 | dbgarg(cmd, "index=%d\n", p->index); | 1361 | dbgarg(cmd, "index=%d\n", p->index); |
1361 | break; | 1362 | break; |
1362 | } | 1363 | } |
1363 | case VIDIOC_S_AUDIO: | 1364 | case VIDIOC_S_AUDIO: |
1364 | { | 1365 | { |
1365 | struct v4l2_audio *p = arg; | 1366 | struct v4l2_audio *p = arg; |
1366 | 1367 | ||
1367 | if (!ops->vidioc_s_audio) | 1368 | if (!ops->vidioc_s_audio) |
1368 | break; | 1369 | break; |
1369 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | 1370 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " |
1370 | "mode=0x%x\n", p->index, p->name, | 1371 | "mode=0x%x\n", p->index, p->name, |
1371 | p->capability, p->mode); | 1372 | p->capability, p->mode); |
1372 | ret = ops->vidioc_s_audio(file, fh, p); | 1373 | ret = ops->vidioc_s_audio(file, fh, p); |
1373 | break; | 1374 | break; |
1374 | } | 1375 | } |
1375 | case VIDIOC_ENUMAUDOUT: | 1376 | case VIDIOC_ENUMAUDOUT: |
1376 | { | 1377 | { |
1377 | struct v4l2_audioout *p = arg; | 1378 | struct v4l2_audioout *p = arg; |
1378 | 1379 | ||
1379 | if (!ops->vidioc_enumaudout) | 1380 | if (!ops->vidioc_enumaudout) |
1380 | break; | 1381 | break; |
1381 | dbgarg(cmd, "Enum for index=%d\n", p->index); | 1382 | dbgarg(cmd, "Enum for index=%d\n", p->index); |
1382 | ret = ops->vidioc_enumaudout(file, fh, p); | 1383 | ret = ops->vidioc_enumaudout(file, fh, p); |
1383 | if (!ret) | 1384 | if (!ret) |
1384 | dbgarg2("index=%d, name=%s, capability=%d, " | 1385 | dbgarg2("index=%d, name=%s, capability=%d, " |
1385 | "mode=%d\n", p->index, p->name, | 1386 | "mode=%d\n", p->index, p->name, |
1386 | p->capability, p->mode); | 1387 | p->capability, p->mode); |
1387 | break; | 1388 | break; |
1388 | } | 1389 | } |
1389 | case VIDIOC_G_AUDOUT: | 1390 | case VIDIOC_G_AUDOUT: |
1390 | { | 1391 | { |
1391 | struct v4l2_audioout *p = arg; | 1392 | struct v4l2_audioout *p = arg; |
1392 | 1393 | ||
1393 | if (!ops->vidioc_g_audout) | 1394 | if (!ops->vidioc_g_audout) |
1394 | break; | 1395 | break; |
1395 | 1396 | ||
1396 | ret = ops->vidioc_g_audout(file, fh, p); | 1397 | ret = ops->vidioc_g_audout(file, fh, p); |
1397 | if (!ret) | 1398 | if (!ret) |
1398 | dbgarg2("index=%d, name=%s, capability=%d, " | 1399 | dbgarg2("index=%d, name=%s, capability=%d, " |
1399 | "mode=%d\n", p->index, p->name, | 1400 | "mode=%d\n", p->index, p->name, |
1400 | p->capability, p->mode); | 1401 | p->capability, p->mode); |
1401 | break; | 1402 | break; |
1402 | } | 1403 | } |
1403 | case VIDIOC_S_AUDOUT: | 1404 | case VIDIOC_S_AUDOUT: |
1404 | { | 1405 | { |
1405 | struct v4l2_audioout *p = arg; | 1406 | struct v4l2_audioout *p = arg; |
1406 | 1407 | ||
1407 | if (!ops->vidioc_s_audout) | 1408 | if (!ops->vidioc_s_audout) |
1408 | break; | 1409 | break; |
1409 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | 1410 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " |
1410 | "mode=%d\n", p->index, p->name, | 1411 | "mode=%d\n", p->index, p->name, |
1411 | p->capability, p->mode); | 1412 | p->capability, p->mode); |
1412 | 1413 | ||
1413 | ret = ops->vidioc_s_audout(file, fh, p); | 1414 | ret = ops->vidioc_s_audout(file, fh, p); |
1414 | break; | 1415 | break; |
1415 | } | 1416 | } |
1416 | case VIDIOC_G_MODULATOR: | 1417 | case VIDIOC_G_MODULATOR: |
1417 | { | 1418 | { |
1418 | struct v4l2_modulator *p = arg; | 1419 | struct v4l2_modulator *p = arg; |
1419 | 1420 | ||
1420 | if (!ops->vidioc_g_modulator) | 1421 | if (!ops->vidioc_g_modulator) |
1421 | break; | 1422 | break; |
1422 | ret = ops->vidioc_g_modulator(file, fh, p); | 1423 | ret = ops->vidioc_g_modulator(file, fh, p); |
1423 | if (!ret) | 1424 | if (!ret) |
1424 | dbgarg(cmd, "index=%d, name=%s, " | 1425 | dbgarg(cmd, "index=%d, name=%s, " |
1425 | "capability=%d, rangelow=%d," | 1426 | "capability=%d, rangelow=%d," |
1426 | " rangehigh=%d, txsubchans=%d\n", | 1427 | " rangehigh=%d, txsubchans=%d\n", |
1427 | p->index, p->name, p->capability, | 1428 | p->index, p->name, p->capability, |
1428 | p->rangelow, p->rangehigh, | 1429 | p->rangelow, p->rangehigh, |
1429 | p->txsubchans); | 1430 | p->txsubchans); |
1430 | break; | 1431 | break; |
1431 | } | 1432 | } |
1432 | case VIDIOC_S_MODULATOR: | 1433 | case VIDIOC_S_MODULATOR: |
1433 | { | 1434 | { |
1434 | struct v4l2_modulator *p = arg; | 1435 | struct v4l2_modulator *p = arg; |
1435 | 1436 | ||
1436 | if (!ops->vidioc_s_modulator) | 1437 | if (!ops->vidioc_s_modulator) |
1437 | break; | 1438 | break; |
1438 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | 1439 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " |
1439 | "rangelow=%d, rangehigh=%d, txsubchans=%d\n", | 1440 | "rangelow=%d, rangehigh=%d, txsubchans=%d\n", |
1440 | p->index, p->name, p->capability, p->rangelow, | 1441 | p->index, p->name, p->capability, p->rangelow, |
1441 | p->rangehigh, p->txsubchans); | 1442 | p->rangehigh, p->txsubchans); |
1442 | ret = ops->vidioc_s_modulator(file, fh, p); | 1443 | ret = ops->vidioc_s_modulator(file, fh, p); |
1443 | break; | 1444 | break; |
1444 | } | 1445 | } |
1445 | case VIDIOC_G_CROP: | 1446 | case VIDIOC_G_CROP: |
1446 | { | 1447 | { |
1447 | struct v4l2_crop *p = arg; | 1448 | struct v4l2_crop *p = arg; |
1448 | 1449 | ||
1449 | if (!ops->vidioc_g_crop) | 1450 | if (!ops->vidioc_g_crop) |
1450 | break; | 1451 | break; |
1451 | 1452 | ||
1452 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | 1453 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); |
1453 | ret = ops->vidioc_g_crop(file, fh, p); | 1454 | ret = ops->vidioc_g_crop(file, fh, p); |
1454 | if (!ret) | 1455 | if (!ret) |
1455 | dbgrect(vfd, "", &p->c); | 1456 | dbgrect(vfd, "", &p->c); |
1456 | break; | 1457 | break; |
1457 | } | 1458 | } |
1458 | case VIDIOC_S_CROP: | 1459 | case VIDIOC_S_CROP: |
1459 | { | 1460 | { |
1460 | struct v4l2_crop *p = arg; | 1461 | struct v4l2_crop *p = arg; |
1461 | 1462 | ||
1462 | if (!ops->vidioc_s_crop) | 1463 | if (!ops->vidioc_s_crop) |
1463 | break; | 1464 | break; |
1464 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | 1465 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); |
1465 | dbgrect(vfd, "", &p->c); | 1466 | dbgrect(vfd, "", &p->c); |
1466 | ret = ops->vidioc_s_crop(file, fh, p); | 1467 | ret = ops->vidioc_s_crop(file, fh, p); |
1467 | break; | 1468 | break; |
1468 | } | 1469 | } |
1469 | case VIDIOC_CROPCAP: | 1470 | case VIDIOC_CROPCAP: |
1470 | { | 1471 | { |
1471 | struct v4l2_cropcap *p = arg; | 1472 | struct v4l2_cropcap *p = arg; |
1472 | 1473 | ||
1473 | /*FIXME: Should also show v4l2_fract pixelaspect */ | 1474 | /*FIXME: Should also show v4l2_fract pixelaspect */ |
1474 | if (!ops->vidioc_cropcap) | 1475 | if (!ops->vidioc_cropcap) |
1475 | break; | 1476 | break; |
1476 | 1477 | ||
1477 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | 1478 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); |
1478 | ret = ops->vidioc_cropcap(file, fh, p); | 1479 | ret = ops->vidioc_cropcap(file, fh, p); |
1479 | if (!ret) { | 1480 | if (!ret) { |
1480 | dbgrect(vfd, "bounds ", &p->bounds); | 1481 | dbgrect(vfd, "bounds ", &p->bounds); |
1481 | dbgrect(vfd, "defrect ", &p->defrect); | 1482 | dbgrect(vfd, "defrect ", &p->defrect); |
1482 | } | 1483 | } |
1483 | break; | 1484 | break; |
1484 | } | 1485 | } |
1485 | case VIDIOC_G_JPEGCOMP: | 1486 | case VIDIOC_G_JPEGCOMP: |
1486 | { | 1487 | { |
1487 | struct v4l2_jpegcompression *p = arg; | 1488 | struct v4l2_jpegcompression *p = arg; |
1488 | 1489 | ||
1489 | if (!ops->vidioc_g_jpegcomp) | 1490 | if (!ops->vidioc_g_jpegcomp) |
1490 | break; | 1491 | break; |
1491 | 1492 | ||
1492 | ret = ops->vidioc_g_jpegcomp(file, fh, p); | 1493 | ret = ops->vidioc_g_jpegcomp(file, fh, p); |
1493 | if (!ret) | 1494 | if (!ret) |
1494 | dbgarg(cmd, "quality=%d, APPn=%d, " | 1495 | dbgarg(cmd, "quality=%d, APPn=%d, " |
1495 | "APP_len=%d, COM_len=%d, " | 1496 | "APP_len=%d, COM_len=%d, " |
1496 | "jpeg_markers=%d\n", | 1497 | "jpeg_markers=%d\n", |
1497 | p->quality, p->APPn, p->APP_len, | 1498 | p->quality, p->APPn, p->APP_len, |
1498 | p->COM_len, p->jpeg_markers); | 1499 | p->COM_len, p->jpeg_markers); |
1499 | break; | 1500 | break; |
1500 | } | 1501 | } |
1501 | case VIDIOC_S_JPEGCOMP: | 1502 | case VIDIOC_S_JPEGCOMP: |
1502 | { | 1503 | { |
1503 | struct v4l2_jpegcompression *p = arg; | 1504 | struct v4l2_jpegcompression *p = arg; |
1504 | 1505 | ||
1505 | if (!ops->vidioc_g_jpegcomp) | 1506 | if (!ops->vidioc_g_jpegcomp) |
1506 | break; | 1507 | break; |
1507 | dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " | 1508 | dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " |
1508 | "COM_len=%d, jpeg_markers=%d\n", | 1509 | "COM_len=%d, jpeg_markers=%d\n", |
1509 | p->quality, p->APPn, p->APP_len, | 1510 | p->quality, p->APPn, p->APP_len, |
1510 | p->COM_len, p->jpeg_markers); | 1511 | p->COM_len, p->jpeg_markers); |
1511 | ret = ops->vidioc_s_jpegcomp(file, fh, p); | 1512 | ret = ops->vidioc_s_jpegcomp(file, fh, p); |
1512 | break; | 1513 | break; |
1513 | } | 1514 | } |
1514 | case VIDIOC_G_ENC_INDEX: | 1515 | case VIDIOC_G_ENC_INDEX: |
1515 | { | 1516 | { |
1516 | struct v4l2_enc_idx *p = arg; | 1517 | struct v4l2_enc_idx *p = arg; |
1517 | 1518 | ||
1518 | if (!ops->vidioc_g_enc_index) | 1519 | if (!ops->vidioc_g_enc_index) |
1519 | break; | 1520 | break; |
1520 | ret = ops->vidioc_g_enc_index(file, fh, p); | 1521 | ret = ops->vidioc_g_enc_index(file, fh, p); |
1521 | if (!ret) | 1522 | if (!ret) |
1522 | dbgarg(cmd, "entries=%d, entries_cap=%d\n", | 1523 | dbgarg(cmd, "entries=%d, entries_cap=%d\n", |
1523 | p->entries, p->entries_cap); | 1524 | p->entries, p->entries_cap); |
1524 | break; | 1525 | break; |
1525 | } | 1526 | } |
1526 | case VIDIOC_ENCODER_CMD: | 1527 | case VIDIOC_ENCODER_CMD: |
1527 | { | 1528 | { |
1528 | struct v4l2_encoder_cmd *p = arg; | 1529 | struct v4l2_encoder_cmd *p = arg; |
1529 | 1530 | ||
1530 | if (!ops->vidioc_encoder_cmd) | 1531 | if (!ops->vidioc_encoder_cmd) |
1531 | break; | 1532 | break; |
1532 | ret = ops->vidioc_encoder_cmd(file, fh, p); | 1533 | ret = ops->vidioc_encoder_cmd(file, fh, p); |
1533 | if (!ret) | 1534 | if (!ret) |
1534 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | 1535 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); |
1535 | break; | 1536 | break; |
1536 | } | 1537 | } |
1537 | case VIDIOC_TRY_ENCODER_CMD: | 1538 | case VIDIOC_TRY_ENCODER_CMD: |
1538 | { | 1539 | { |
1539 | struct v4l2_encoder_cmd *p = arg; | 1540 | struct v4l2_encoder_cmd *p = arg; |
1540 | 1541 | ||
1541 | if (!ops->vidioc_try_encoder_cmd) | 1542 | if (!ops->vidioc_try_encoder_cmd) |
1542 | break; | 1543 | break; |
1543 | ret = ops->vidioc_try_encoder_cmd(file, fh, p); | 1544 | ret = ops->vidioc_try_encoder_cmd(file, fh, p); |
1544 | if (!ret) | 1545 | if (!ret) |
1545 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | 1546 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); |
1546 | break; | 1547 | break; |
1547 | } | 1548 | } |
1548 | case VIDIOC_G_PARM: | 1549 | case VIDIOC_G_PARM: |
1549 | { | 1550 | { |
1550 | struct v4l2_streamparm *p = arg; | 1551 | struct v4l2_streamparm *p = arg; |
1551 | 1552 | ||
1552 | if (ops->vidioc_g_parm) { | 1553 | if (ops->vidioc_g_parm) { |
1553 | ret = ops->vidioc_g_parm(file, fh, p); | 1554 | ret = ops->vidioc_g_parm(file, fh, p); |
1554 | } else { | 1555 | } else { |
1555 | if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1556 | if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1556 | return -EINVAL; | 1557 | return -EINVAL; |
1557 | 1558 | ||
1558 | v4l2_video_std_frame_period(vfd->current_norm, | 1559 | v4l2_video_std_frame_period(vfd->current_norm, |
1559 | &p->parm.capture.timeperframe); | 1560 | &p->parm.capture.timeperframe); |
1560 | ret = 0; | 1561 | ret = 0; |
1561 | } | 1562 | } |
1562 | 1563 | ||
1563 | dbgarg(cmd, "type=%d\n", p->type); | 1564 | dbgarg(cmd, "type=%d\n", p->type); |
1564 | break; | 1565 | break; |
1565 | } | 1566 | } |
1566 | case VIDIOC_S_PARM: | 1567 | case VIDIOC_S_PARM: |
1567 | { | 1568 | { |
1568 | struct v4l2_streamparm *p = arg; | 1569 | struct v4l2_streamparm *p = arg; |
1569 | 1570 | ||
1570 | if (!ops->vidioc_s_parm) | 1571 | if (!ops->vidioc_s_parm) |
1571 | break; | 1572 | break; |
1572 | dbgarg(cmd, "type=%d\n", p->type); | 1573 | dbgarg(cmd, "type=%d\n", p->type); |
1573 | ret = ops->vidioc_s_parm(file, fh, p); | 1574 | ret = ops->vidioc_s_parm(file, fh, p); |
1574 | break; | 1575 | break; |
1575 | } | 1576 | } |
1576 | case VIDIOC_G_TUNER: | 1577 | case VIDIOC_G_TUNER: |
1577 | { | 1578 | { |
1578 | struct v4l2_tuner *p = arg; | 1579 | struct v4l2_tuner *p = arg; |
1579 | 1580 | ||
1580 | if (!ops->vidioc_g_tuner) | 1581 | if (!ops->vidioc_g_tuner) |
1581 | break; | 1582 | break; |
1582 | 1583 | ||
1583 | ret = ops->vidioc_g_tuner(file, fh, p); | 1584 | ret = ops->vidioc_g_tuner(file, fh, p); |
1584 | if (!ret) | 1585 | if (!ret) |
1585 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | 1586 | dbgarg(cmd, "index=%d, name=%s, type=%d, " |
1586 | "capability=0x%x, rangelow=%d, " | 1587 | "capability=0x%x, rangelow=%d, " |
1587 | "rangehigh=%d, signal=%d, afc=%d, " | 1588 | "rangehigh=%d, signal=%d, afc=%d, " |
1588 | "rxsubchans=0x%x, audmode=%d\n", | 1589 | "rxsubchans=0x%x, audmode=%d\n", |
1589 | p->index, p->name, p->type, | 1590 | p->index, p->name, p->type, |
1590 | p->capability, p->rangelow, | 1591 | p->capability, p->rangelow, |
1591 | p->rangehigh, p->signal, p->afc, | 1592 | p->rangehigh, p->signal, p->afc, |
1592 | p->rxsubchans, p->audmode); | 1593 | p->rxsubchans, p->audmode); |
1593 | break; | 1594 | break; |
1594 | } | 1595 | } |
1595 | case VIDIOC_S_TUNER: | 1596 | case VIDIOC_S_TUNER: |
1596 | { | 1597 | { |
1597 | struct v4l2_tuner *p = arg; | 1598 | struct v4l2_tuner *p = arg; |
1598 | 1599 | ||
1599 | if (!ops->vidioc_s_tuner) | 1600 | if (!ops->vidioc_s_tuner) |
1600 | break; | 1601 | break; |
1601 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | 1602 | dbgarg(cmd, "index=%d, name=%s, type=%d, " |
1602 | "capability=0x%x, rangelow=%d, " | 1603 | "capability=0x%x, rangelow=%d, " |
1603 | "rangehigh=%d, signal=%d, afc=%d, " | 1604 | "rangehigh=%d, signal=%d, afc=%d, " |
1604 | "rxsubchans=0x%x, audmode=%d\n", | 1605 | "rxsubchans=0x%x, audmode=%d\n", |
1605 | p->index, p->name, p->type, | 1606 | p->index, p->name, p->type, |
1606 | p->capability, p->rangelow, | 1607 | p->capability, p->rangelow, |
1607 | p->rangehigh, p->signal, p->afc, | 1608 | p->rangehigh, p->signal, p->afc, |
1608 | p->rxsubchans, p->audmode); | 1609 | p->rxsubchans, p->audmode); |
1609 | ret = ops->vidioc_s_tuner(file, fh, p); | 1610 | ret = ops->vidioc_s_tuner(file, fh, p); |
1610 | break; | 1611 | break; |
1611 | } | 1612 | } |
1612 | case VIDIOC_G_FREQUENCY: | 1613 | case VIDIOC_G_FREQUENCY: |
1613 | { | 1614 | { |
1614 | struct v4l2_frequency *p = arg; | 1615 | struct v4l2_frequency *p = arg; |
1615 | 1616 | ||
1616 | if (!ops->vidioc_g_frequency) | 1617 | if (!ops->vidioc_g_frequency) |
1617 | break; | 1618 | break; |
1618 | 1619 | ||
1619 | ret = ops->vidioc_g_frequency(file, fh, p); | 1620 | ret = ops->vidioc_g_frequency(file, fh, p); |
1620 | if (!ret) | 1621 | if (!ret) |
1621 | dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", | 1622 | dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", |
1622 | p->tuner, p->type, p->frequency); | 1623 | p->tuner, p->type, p->frequency); |
1623 | break; | 1624 | break; |
1624 | } | 1625 | } |
1625 | case VIDIOC_S_FREQUENCY: | 1626 | case VIDIOC_S_FREQUENCY: |
1626 | { | 1627 | { |
1627 | struct v4l2_frequency *p = arg; | 1628 | struct v4l2_frequency *p = arg; |
1628 | 1629 | ||
1629 | if (!ops->vidioc_s_frequency) | 1630 | if (!ops->vidioc_s_frequency) |
1630 | break; | 1631 | break; |
1631 | dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", | 1632 | dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", |
1632 | p->tuner, p->type, p->frequency); | 1633 | p->tuner, p->type, p->frequency); |
1633 | ret = ops->vidioc_s_frequency(file, fh, p); | 1634 | ret = ops->vidioc_s_frequency(file, fh, p); |
1634 | break; | 1635 | break; |
1635 | } | 1636 | } |
1636 | case VIDIOC_G_SLICED_VBI_CAP: | 1637 | case VIDIOC_G_SLICED_VBI_CAP: |
1637 | { | 1638 | { |
1638 | struct v4l2_sliced_vbi_cap *p = arg; | 1639 | struct v4l2_sliced_vbi_cap *p = arg; |
1639 | 1640 | ||
1640 | if (!ops->vidioc_g_sliced_vbi_cap) | 1641 | if (!ops->vidioc_g_sliced_vbi_cap) |
1641 | break; | 1642 | break; |
1642 | 1643 | ||
1643 | /* Clear up to type, everything after type is zerod already */ | 1644 | /* Clear up to type, everything after type is zerod already */ |
1644 | memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); | 1645 | memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); |
1645 | 1646 | ||
1646 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | 1647 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); |
1647 | ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); | 1648 | ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); |
1648 | if (!ret) | 1649 | if (!ret) |
1649 | dbgarg2("service_set=%d\n", p->service_set); | 1650 | dbgarg2("service_set=%d\n", p->service_set); |
1650 | break; | 1651 | break; |
1651 | } | 1652 | } |
1652 | case VIDIOC_LOG_STATUS: | 1653 | case VIDIOC_LOG_STATUS: |
1653 | { | 1654 | { |
1654 | if (!ops->vidioc_log_status) | 1655 | if (!ops->vidioc_log_status) |
1655 | break; | 1656 | break; |
1656 | ret = ops->vidioc_log_status(file, fh); | 1657 | ret = ops->vidioc_log_status(file, fh); |
1657 | break; | 1658 | break; |
1658 | } | 1659 | } |
1659 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1660 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1660 | case VIDIOC_DBG_G_REGISTER: | 1661 | case VIDIOC_DBG_G_REGISTER: |
1661 | { | 1662 | { |
1662 | struct v4l2_dbg_register *p = arg; | 1663 | struct v4l2_dbg_register *p = arg; |
1663 | 1664 | ||
1664 | if (!capable(CAP_SYS_ADMIN)) | 1665 | if (!capable(CAP_SYS_ADMIN)) |
1665 | ret = -EPERM; | 1666 | ret = -EPERM; |
1666 | else if (ops->vidioc_g_register) | 1667 | else if (ops->vidioc_g_register) |
1667 | ret = ops->vidioc_g_register(file, fh, p); | 1668 | ret = ops->vidioc_g_register(file, fh, p); |
1668 | break; | 1669 | break; |
1669 | } | 1670 | } |
1670 | case VIDIOC_DBG_S_REGISTER: | 1671 | case VIDIOC_DBG_S_REGISTER: |
1671 | { | 1672 | { |
1672 | struct v4l2_dbg_register *p = arg; | 1673 | struct v4l2_dbg_register *p = arg; |
1673 | 1674 | ||
1674 | if (!capable(CAP_SYS_ADMIN)) | 1675 | if (!capable(CAP_SYS_ADMIN)) |
1675 | ret = -EPERM; | 1676 | ret = -EPERM; |
1676 | else if (ops->vidioc_s_register) | 1677 | else if (ops->vidioc_s_register) |
1677 | ret = ops->vidioc_s_register(file, fh, p); | 1678 | ret = ops->vidioc_s_register(file, fh, p); |
1678 | break; | 1679 | break; |
1679 | } | 1680 | } |
1680 | #endif | 1681 | #endif |
1681 | case VIDIOC_DBG_G_CHIP_IDENT: | 1682 | case VIDIOC_DBG_G_CHIP_IDENT: |
1682 | { | 1683 | { |
1683 | struct v4l2_dbg_chip_ident *p = arg; | 1684 | struct v4l2_dbg_chip_ident *p = arg; |
1684 | 1685 | ||
1685 | if (!ops->vidioc_g_chip_ident) | 1686 | if (!ops->vidioc_g_chip_ident) |
1686 | break; | 1687 | break; |
1687 | p->ident = V4L2_IDENT_NONE; | 1688 | p->ident = V4L2_IDENT_NONE; |
1688 | p->revision = 0; | 1689 | p->revision = 0; |
1689 | ret = ops->vidioc_g_chip_ident(file, fh, p); | 1690 | ret = ops->vidioc_g_chip_ident(file, fh, p); |
1690 | if (!ret) | 1691 | if (!ret) |
1691 | dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); | 1692 | dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); |
1692 | break; | 1693 | break; |
1693 | } | 1694 | } |
1694 | case VIDIOC_G_CHIP_IDENT_OLD: | 1695 | case VIDIOC_G_CHIP_IDENT_OLD: |
1695 | printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n"); | 1696 | printk(KERN_ERR "VIDIOC_G_CHIP_IDENT has been deprecated and will disappear in 2.6.30.\n"); |
1696 | printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n"); | 1697 | printk(KERN_ERR "It is a debugging ioctl and must not be used in applications!\n"); |
1697 | return -EINVAL; | 1698 | return -EINVAL; |
1698 | 1699 | ||
1699 | case VIDIOC_S_HW_FREQ_SEEK: | 1700 | case VIDIOC_S_HW_FREQ_SEEK: |
1700 | { | 1701 | { |
1701 | struct v4l2_hw_freq_seek *p = arg; | 1702 | struct v4l2_hw_freq_seek *p = arg; |
1702 | 1703 | ||
1703 | if (!ops->vidioc_s_hw_freq_seek) | 1704 | if (!ops->vidioc_s_hw_freq_seek) |
1704 | break; | 1705 | break; |
1705 | dbgarg(cmd, | 1706 | dbgarg(cmd, |
1706 | "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", | 1707 | "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", |
1707 | p->tuner, p->type, p->seek_upward, p->wrap_around); | 1708 | p->tuner, p->type, p->seek_upward, p->wrap_around); |
1708 | ret = ops->vidioc_s_hw_freq_seek(file, fh, p); | 1709 | ret = ops->vidioc_s_hw_freq_seek(file, fh, p); |
1709 | break; | 1710 | break; |
1710 | } | 1711 | } |
1711 | case VIDIOC_ENUM_FRAMESIZES: | 1712 | case VIDIOC_ENUM_FRAMESIZES: |
1712 | { | 1713 | { |
1713 | struct v4l2_frmsizeenum *p = arg; | 1714 | struct v4l2_frmsizeenum *p = arg; |
1714 | 1715 | ||
1715 | if (!ops->vidioc_enum_framesizes) | 1716 | if (!ops->vidioc_enum_framesizes) |
1716 | break; | 1717 | break; |
1717 | 1718 | ||
1718 | ret = ops->vidioc_enum_framesizes(file, fh, p); | 1719 | ret = ops->vidioc_enum_framesizes(file, fh, p); |
1719 | dbgarg(cmd, | 1720 | dbgarg(cmd, |
1720 | "index=%d, pixelformat=%d, type=%d ", | 1721 | "index=%d, pixelformat=%d, type=%d ", |
1721 | p->index, p->pixel_format, p->type); | 1722 | p->index, p->pixel_format, p->type); |
1722 | switch (p->type) { | 1723 | switch (p->type) { |
1723 | case V4L2_FRMSIZE_TYPE_DISCRETE: | 1724 | case V4L2_FRMSIZE_TYPE_DISCRETE: |
1724 | dbgarg2("width = %d, height=%d\n", | 1725 | dbgarg2("width = %d, height=%d\n", |
1725 | p->discrete.width, p->discrete.height); | 1726 | p->discrete.width, p->discrete.height); |
1726 | break; | 1727 | break; |
1727 | case V4L2_FRMSIZE_TYPE_STEPWISE: | 1728 | case V4L2_FRMSIZE_TYPE_STEPWISE: |
1728 | dbgarg2("min %dx%d, max %dx%d, step %dx%d\n", | 1729 | dbgarg2("min %dx%d, max %dx%d, step %dx%d\n", |
1729 | p->stepwise.min_width, p->stepwise.min_height, | 1730 | p->stepwise.min_width, p->stepwise.min_height, |
1730 | p->stepwise.step_width, p->stepwise.step_height, | 1731 | p->stepwise.step_width, p->stepwise.step_height, |
1731 | p->stepwise.max_width, p->stepwise.max_height); | 1732 | p->stepwise.max_width, p->stepwise.max_height); |
1732 | break; | 1733 | break; |
1733 | case V4L2_FRMSIZE_TYPE_CONTINUOUS: | 1734 | case V4L2_FRMSIZE_TYPE_CONTINUOUS: |
1734 | dbgarg2("continuous\n"); | 1735 | dbgarg2("continuous\n"); |
1735 | break; | 1736 | break; |
1736 | default: | 1737 | default: |
1737 | dbgarg2("- Unknown type!\n"); | 1738 | dbgarg2("- Unknown type!\n"); |
1738 | } | 1739 | } |
1739 | 1740 | ||
1740 | break; | 1741 | break; |
1741 | } | 1742 | } |
1742 | case VIDIOC_ENUM_FRAMEINTERVALS: | 1743 | case VIDIOC_ENUM_FRAMEINTERVALS: |
1743 | { | 1744 | { |
1744 | struct v4l2_frmivalenum *p = arg; | 1745 | struct v4l2_frmivalenum *p = arg; |
1745 | 1746 | ||
1746 | if (!ops->vidioc_enum_frameintervals) | 1747 | if (!ops->vidioc_enum_frameintervals) |
1747 | break; | 1748 | break; |
1748 | 1749 | ||
1749 | ret = ops->vidioc_enum_frameintervals(file, fh, p); | 1750 | ret = ops->vidioc_enum_frameintervals(file, fh, p); |
1750 | dbgarg(cmd, | 1751 | dbgarg(cmd, |
1751 | "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", | 1752 | "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", |
1752 | p->index, p->pixel_format, | 1753 | p->index, p->pixel_format, |
1753 | p->width, p->height, p->type); | 1754 | p->width, p->height, p->type); |
1754 | switch (p->type) { | 1755 | switch (p->type) { |
1755 | case V4L2_FRMIVAL_TYPE_DISCRETE: | 1756 | case V4L2_FRMIVAL_TYPE_DISCRETE: |
1756 | dbgarg2("fps=%d/%d\n", | 1757 | dbgarg2("fps=%d/%d\n", |
1757 | p->discrete.numerator, | 1758 | p->discrete.numerator, |
1758 | p->discrete.denominator); | 1759 | p->discrete.denominator); |
1759 | break; | 1760 | break; |
1760 | case V4L2_FRMIVAL_TYPE_STEPWISE: | 1761 | case V4L2_FRMIVAL_TYPE_STEPWISE: |
1761 | dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", | 1762 | dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", |
1762 | p->stepwise.min.numerator, | 1763 | p->stepwise.min.numerator, |
1763 | p->stepwise.min.denominator, | 1764 | p->stepwise.min.denominator, |
1764 | p->stepwise.max.numerator, | 1765 | p->stepwise.max.numerator, |
1765 | p->stepwise.max.denominator, | 1766 | p->stepwise.max.denominator, |
1766 | p->stepwise.step.numerator, | 1767 | p->stepwise.step.numerator, |
1767 | p->stepwise.step.denominator); | 1768 | p->stepwise.step.denominator); |
1768 | break; | 1769 | break; |
1769 | case V4L2_FRMIVAL_TYPE_CONTINUOUS: | 1770 | case V4L2_FRMIVAL_TYPE_CONTINUOUS: |
1770 | dbgarg2("continuous\n"); | 1771 | dbgarg2("continuous\n"); |
1771 | break; | 1772 | break; |
1772 | default: | 1773 | default: |
1773 | dbgarg2("- Unknown type!\n"); | 1774 | dbgarg2("- Unknown type!\n"); |
1774 | } | 1775 | } |
1775 | break; | 1776 | break; |
1776 | } | 1777 | } |
1777 | 1778 | ||
1778 | default: | 1779 | default: |
1779 | { | 1780 | { |
1780 | if (!ops->vidioc_default) | 1781 | if (!ops->vidioc_default) |
1781 | break; | 1782 | break; |
1782 | ret = ops->vidioc_default(file, fh, cmd, arg); | 1783 | ret = ops->vidioc_default(file, fh, cmd, arg); |
1783 | break; | 1784 | break; |
1784 | } | 1785 | } |
1785 | } /* switch */ | 1786 | } /* switch */ |
1786 | 1787 | ||
1787 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | 1788 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { |
1788 | if (ret < 0) { | 1789 | if (ret < 0) { |
1789 | v4l_print_ioctl(vfd->name, cmd); | 1790 | v4l_print_ioctl(vfd->name, cmd); |
1790 | printk(KERN_CONT " error %ld\n", ret); | 1791 | printk(KERN_CONT " error %ld\n", ret); |
1791 | } | 1792 | } |
1792 | } | 1793 | } |
1793 | 1794 | ||
1794 | return ret; | 1795 | return ret; |
1795 | } | 1796 | } |
1796 | 1797 | ||
1797 | /* In some cases, only a few fields are used as input, i.e. when the app sets | 1798 | /* In some cases, only a few fields are used as input, i.e. when the app sets |
1798 | * "index" and then the driver fills in the rest of the structure for the thing | 1799 | * "index" and then the driver fills in the rest of the structure for the thing |
1799 | * with that index. We only need to copy up the first non-input field. */ | 1800 | * with that index. We only need to copy up the first non-input field. */ |
1800 | static unsigned long cmd_input_size(unsigned int cmd) | 1801 | static unsigned long cmd_input_size(unsigned int cmd) |
1801 | { | 1802 | { |
1802 | /* Size of structure up to and including 'field' */ | 1803 | /* Size of structure up to and including 'field' */ |
1803 | #define CMDINSIZE(cmd, type, field) case _IOC_NR(VIDIOC_##cmd): return \ | 1804 | #define CMDINSIZE(cmd, type, field) case _IOC_NR(VIDIOC_##cmd): return \ |
1804 | offsetof(struct v4l2_##type, field) + \ | 1805 | offsetof(struct v4l2_##type, field) + \ |
1805 | sizeof(((struct v4l2_##type *)0)->field); | 1806 | sizeof(((struct v4l2_##type *)0)->field); |
1806 | 1807 | ||
1807 | switch (_IOC_NR(cmd)) { | 1808 | switch (_IOC_NR(cmd)) { |
1808 | CMDINSIZE(ENUM_FMT, fmtdesc, type); | 1809 | CMDINSIZE(ENUM_FMT, fmtdesc, type); |
1809 | CMDINSIZE(G_FMT, format, type); | 1810 | CMDINSIZE(G_FMT, format, type); |
1810 | CMDINSIZE(QUERYBUF, buffer, type); | 1811 | CMDINSIZE(QUERYBUF, buffer, type); |
1811 | CMDINSIZE(G_PARM, streamparm, type); | 1812 | CMDINSIZE(G_PARM, streamparm, type); |
1812 | CMDINSIZE(ENUMSTD, standard, index); | 1813 | CMDINSIZE(ENUMSTD, standard, index); |
1813 | CMDINSIZE(ENUMINPUT, input, index); | 1814 | CMDINSIZE(ENUMINPUT, input, index); |
1814 | CMDINSIZE(G_CTRL, control, id); | 1815 | CMDINSIZE(G_CTRL, control, id); |
1815 | CMDINSIZE(G_TUNER, tuner, index); | 1816 | CMDINSIZE(G_TUNER, tuner, index); |
1816 | CMDINSIZE(QUERYCTRL, queryctrl, id); | 1817 | CMDINSIZE(QUERYCTRL, queryctrl, id); |
1817 | CMDINSIZE(QUERYMENU, querymenu, index); | 1818 | CMDINSIZE(QUERYMENU, querymenu, index); |
1818 | CMDINSIZE(ENUMOUTPUT, output, index); | 1819 | CMDINSIZE(ENUMOUTPUT, output, index); |
1819 | CMDINSIZE(G_MODULATOR, modulator, index); | 1820 | CMDINSIZE(G_MODULATOR, modulator, index); |
1820 | CMDINSIZE(G_FREQUENCY, frequency, tuner); | 1821 | CMDINSIZE(G_FREQUENCY, frequency, tuner); |
1821 | CMDINSIZE(CROPCAP, cropcap, type); | 1822 | CMDINSIZE(CROPCAP, cropcap, type); |
1822 | CMDINSIZE(G_CROP, crop, type); | 1823 | CMDINSIZE(G_CROP, crop, type); |
1823 | CMDINSIZE(ENUMAUDIO, audio, index); | 1824 | CMDINSIZE(ENUMAUDIO, audio, index); |
1824 | CMDINSIZE(ENUMAUDOUT, audioout, index); | 1825 | CMDINSIZE(ENUMAUDOUT, audioout, index); |
1825 | CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); | 1826 | CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); |
1826 | CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); | 1827 | CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); |
1827 | CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); | 1828 | CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); |
1828 | CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); | 1829 | CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); |
1829 | CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); | 1830 | CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); |
1830 | default: | 1831 | default: |
1831 | return _IOC_SIZE(cmd); | 1832 | return _IOC_SIZE(cmd); |
1832 | } | 1833 | } |
1833 | } | 1834 | } |
1834 | 1835 | ||
1835 | long video_ioctl2(struct file *file, | 1836 | long video_ioctl2(struct file *file, |
1836 | unsigned int cmd, unsigned long arg) | 1837 | unsigned int cmd, unsigned long arg) |
1837 | { | 1838 | { |
1838 | char sbuf[128]; | 1839 | char sbuf[128]; |
1839 | void *mbuf = NULL; | 1840 | void *mbuf = NULL; |
1840 | void *parg = NULL; | 1841 | void *parg = NULL; |
1841 | long err = -EINVAL; | 1842 | long err = -EINVAL; |
1842 | int is_ext_ctrl; | 1843 | int is_ext_ctrl; |
1843 | size_t ctrls_size = 0; | 1844 | size_t ctrls_size = 0; |
1844 | void __user *user_ptr = NULL; | 1845 | void __user *user_ptr = NULL; |
1845 | 1846 | ||
1846 | #ifdef __OLD_VIDIOC_ | 1847 | #ifdef __OLD_VIDIOC_ |
1847 | cmd = video_fix_command(cmd); | 1848 | cmd = video_fix_command(cmd); |
1848 | #endif | 1849 | #endif |
1849 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | 1850 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || |
1850 | cmd == VIDIOC_TRY_EXT_CTRLS); | 1851 | cmd == VIDIOC_TRY_EXT_CTRLS); |
1851 | 1852 | ||
1852 | /* Copy arguments into temp kernel buffer */ | 1853 | /* Copy arguments into temp kernel buffer */ |
1853 | if (_IOC_DIR(cmd) != _IOC_NONE) { | 1854 | if (_IOC_DIR(cmd) != _IOC_NONE) { |
1854 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | 1855 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { |
1855 | parg = sbuf; | 1856 | parg = sbuf; |
1856 | } else { | 1857 | } else { |
1857 | /* too big to allocate from stack */ | 1858 | /* too big to allocate from stack */ |
1858 | mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); | 1859 | mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); |
1859 | if (NULL == mbuf) | 1860 | if (NULL == mbuf) |
1860 | return -ENOMEM; | 1861 | return -ENOMEM; |
1861 | parg = mbuf; | 1862 | parg = mbuf; |
1862 | } | 1863 | } |
1863 | 1864 | ||
1864 | err = -EFAULT; | 1865 | err = -EFAULT; |
1865 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 1866 | if (_IOC_DIR(cmd) & _IOC_WRITE) { |
1866 | unsigned long n = cmd_input_size(cmd); | 1867 | unsigned long n = cmd_input_size(cmd); |
1867 | 1868 | ||
1868 | if (copy_from_user(parg, (void __user *)arg, n)) | 1869 | if (copy_from_user(parg, (void __user *)arg, n)) |
1869 | goto out; | 1870 | goto out; |
1870 | 1871 | ||
1871 | /* zero out anything we don't copy from userspace */ | 1872 | /* zero out anything we don't copy from userspace */ |
1872 | if (n < _IOC_SIZE(cmd)) | 1873 | if (n < _IOC_SIZE(cmd)) |
1873 | memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); | 1874 | memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); |
1874 | } else { | 1875 | } else { |
1875 | /* read-only ioctl */ | 1876 | /* read-only ioctl */ |
1876 | memset(parg, 0, _IOC_SIZE(cmd)); | 1877 | memset(parg, 0, _IOC_SIZE(cmd)); |
1877 | } | 1878 | } |
1878 | } | 1879 | } |
1879 | 1880 | ||
1880 | if (is_ext_ctrl) { | 1881 | if (is_ext_ctrl) { |
1881 | struct v4l2_ext_controls *p = parg; | 1882 | struct v4l2_ext_controls *p = parg; |
1882 | 1883 | ||
1883 | /* In case of an error, tell the caller that it wasn't | 1884 | /* In case of an error, tell the caller that it wasn't |
1884 | a specific control that caused it. */ | 1885 | a specific control that caused it. */ |
1885 | p->error_idx = p->count; | 1886 | p->error_idx = p->count; |
1886 | user_ptr = (void __user *)p->controls; | 1887 | user_ptr = (void __user *)p->controls; |
1887 | if (p->count) { | 1888 | if (p->count) { |
1888 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | 1889 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; |
1889 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | 1890 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ |
1890 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | 1891 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); |
1891 | err = -ENOMEM; | 1892 | err = -ENOMEM; |
1892 | if (NULL == mbuf) | 1893 | if (NULL == mbuf) |
1893 | goto out_ext_ctrl; | 1894 | goto out_ext_ctrl; |
1894 | err = -EFAULT; | 1895 | err = -EFAULT; |
1895 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | 1896 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) |
1896 | goto out_ext_ctrl; | 1897 | goto out_ext_ctrl; |
1897 | p->controls = mbuf; | 1898 | p->controls = mbuf; |
1898 | } | 1899 | } |
1899 | } | 1900 | } |
1900 | 1901 | ||
1901 | /* Handles IOCTL */ | 1902 | /* Handles IOCTL */ |
1902 | err = __video_do_ioctl(file, cmd, parg); | 1903 | err = __video_do_ioctl(file, cmd, parg); |
1903 | if (err == -ENOIOCTLCMD) | 1904 | if (err == -ENOIOCTLCMD) |
1904 | err = -EINVAL; | 1905 | err = -EINVAL; |
1905 | if (is_ext_ctrl) { | 1906 | if (is_ext_ctrl) { |
1906 | struct v4l2_ext_controls *p = parg; | 1907 | struct v4l2_ext_controls *p = parg; |
1907 | 1908 | ||
1908 | p->controls = (void *)user_ptr; | 1909 | p->controls = (void *)user_ptr; |
1909 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | 1910 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) |
1910 | err = -EFAULT; | 1911 | err = -EFAULT; |
1911 | goto out_ext_ctrl; | 1912 | goto out_ext_ctrl; |
1912 | } | 1913 | } |
1913 | if (err < 0) | 1914 | if (err < 0) |
1914 | goto out; | 1915 | goto out; |
1915 | 1916 | ||
1916 | out_ext_ctrl: | 1917 | out_ext_ctrl: |
1917 | /* Copy results into user buffer */ | 1918 | /* Copy results into user buffer */ |
1918 | switch (_IOC_DIR(cmd)) { | 1919 | switch (_IOC_DIR(cmd)) { |
1919 | case _IOC_READ: | 1920 | case _IOC_READ: |
1920 | case (_IOC_WRITE | _IOC_READ): | 1921 | case (_IOC_WRITE | _IOC_READ): |
1921 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | 1922 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) |
1922 | err = -EFAULT; | 1923 | err = -EFAULT; |
1923 | break; | 1924 | break; |
1924 | } | 1925 | } |
1925 | 1926 | ||
1926 | out: | 1927 | out: |
1927 | kfree(mbuf); | 1928 | kfree(mbuf); |
1928 | return err; | 1929 | return err; |
1929 | } | 1930 | } |
1930 | EXPORT_SYMBOL(video_ioctl2); | 1931 | EXPORT_SYMBOL(video_ioctl2); |
1931 | 1932 |
drivers/media/video/vivi.c
1 | /* | 1 | /* |
2 | * Virtual Video driver - This code emulates a real video device with v4l2 api | 2 | * Virtual Video driver - This code emulates a real video device with v4l2 api |
3 | * | 3 | * |
4 | * Copyright (c) 2006 by: | 4 | * Copyright (c) 2006 by: |
5 | * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> | 5 | * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> |
6 | * Ted Walther <ted--a.t--enumera.com> | 6 | * Ted Walther <ted--a.t--enumera.com> |
7 | * John Sokol <sokol--a.t--videotechnology.com> | 7 | * John Sokol <sokol--a.t--videotechnology.com> |
8 | * http://v4l.videotechnology.com/ | 8 | * http://v4l.videotechnology.com/ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the BSD Licence, GNU General Public License | 11 | * it under the terms of the BSD Licence, GNU General Public License |
12 | * as published by the Free Software Foundation; either version 2 of the | 12 | * as published by the Free Software Foundation; either version 2 of the |
13 | * License, or (at your option) any later version | 13 | * License, or (at your option) any later version |
14 | */ | 14 | */ |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/random.h> | 26 | #include <linux/random.h> |
27 | #include <linux/version.h> | 27 | #include <linux/version.h> |
28 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
29 | #include <linux/videodev2.h> | 29 | #include <linux/videodev2.h> |
30 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
31 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
32 | /* Include V4L1 specific functions. Should be removed soon */ | ||
33 | #include <linux/videodev.h> | ||
34 | #endif | ||
35 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
36 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
37 | #include <linux/highmem.h> | 33 | #include <linux/highmem.h> |
38 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
39 | #include <media/videobuf-vmalloc.h> | 35 | #include <media/videobuf-vmalloc.h> |
40 | #include <media/v4l2-device.h> | 36 | #include <media/v4l2-device.h> |
41 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
42 | #include "font.h" | 38 | #include "font.h" |
43 | 39 | ||
44 | #define VIVI_MODULE_NAME "vivi" | 40 | #define VIVI_MODULE_NAME "vivi" |
45 | 41 | ||
46 | /* Wake up at about 30 fps */ | 42 | /* Wake up at about 30 fps */ |
47 | #define WAKE_NUMERATOR 30 | 43 | #define WAKE_NUMERATOR 30 |
48 | #define WAKE_DENOMINATOR 1001 | 44 | #define WAKE_DENOMINATOR 1001 |
49 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | 45 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ |
50 | 46 | ||
51 | #define VIVI_MAJOR_VERSION 0 | 47 | #define VIVI_MAJOR_VERSION 0 |
52 | #define VIVI_MINOR_VERSION 6 | 48 | #define VIVI_MINOR_VERSION 6 |
53 | #define VIVI_RELEASE 0 | 49 | #define VIVI_RELEASE 0 |
54 | #define VIVI_VERSION \ | 50 | #define VIVI_VERSION \ |
55 | KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) | 51 | KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) |
56 | 52 | ||
57 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); | 53 | MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); |
58 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); | 54 | MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); |
59 | MODULE_LICENSE("Dual BSD/GPL"); | 55 | MODULE_LICENSE("Dual BSD/GPL"); |
60 | 56 | ||
61 | static unsigned video_nr = -1; | 57 | static unsigned video_nr = -1; |
62 | module_param(video_nr, uint, 0644); | 58 | module_param(video_nr, uint, 0644); |
63 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | 59 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); |
64 | 60 | ||
65 | static unsigned n_devs = 1; | 61 | static unsigned n_devs = 1; |
66 | module_param(n_devs, uint, 0644); | 62 | module_param(n_devs, uint, 0644); |
67 | MODULE_PARM_DESC(n_devs, "number of video devices to create"); | 63 | MODULE_PARM_DESC(n_devs, "number of video devices to create"); |
68 | 64 | ||
69 | static unsigned debug; | 65 | static unsigned debug; |
70 | module_param(debug, uint, 0644); | 66 | module_param(debug, uint, 0644); |
71 | MODULE_PARM_DESC(debug, "activates debug info"); | 67 | MODULE_PARM_DESC(debug, "activates debug info"); |
72 | 68 | ||
73 | static unsigned int vid_limit = 16; | 69 | static unsigned int vid_limit = 16; |
74 | module_param(vid_limit, uint, 0644); | 70 | module_param(vid_limit, uint, 0644); |
75 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | 71 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); |
76 | 72 | ||
77 | 73 | ||
78 | /* supported controls */ | 74 | /* supported controls */ |
79 | static struct v4l2_queryctrl vivi_qctrl[] = { | 75 | static struct v4l2_queryctrl vivi_qctrl[] = { |
80 | { | 76 | { |
81 | .id = V4L2_CID_AUDIO_VOLUME, | 77 | .id = V4L2_CID_AUDIO_VOLUME, |
82 | .name = "Volume", | 78 | .name = "Volume", |
83 | .minimum = 0, | 79 | .minimum = 0, |
84 | .maximum = 65535, | 80 | .maximum = 65535, |
85 | .step = 65535/100, | 81 | .step = 65535/100, |
86 | .default_value = 65535, | 82 | .default_value = 65535, |
87 | .flags = V4L2_CTRL_FLAG_SLIDER, | 83 | .flags = V4L2_CTRL_FLAG_SLIDER, |
88 | .type = V4L2_CTRL_TYPE_INTEGER, | 84 | .type = V4L2_CTRL_TYPE_INTEGER, |
89 | }, { | 85 | }, { |
90 | .id = V4L2_CID_BRIGHTNESS, | 86 | .id = V4L2_CID_BRIGHTNESS, |
91 | .type = V4L2_CTRL_TYPE_INTEGER, | 87 | .type = V4L2_CTRL_TYPE_INTEGER, |
92 | .name = "Brightness", | 88 | .name = "Brightness", |
93 | .minimum = 0, | 89 | .minimum = 0, |
94 | .maximum = 255, | 90 | .maximum = 255, |
95 | .step = 1, | 91 | .step = 1, |
96 | .default_value = 127, | 92 | .default_value = 127, |
97 | .flags = V4L2_CTRL_FLAG_SLIDER, | 93 | .flags = V4L2_CTRL_FLAG_SLIDER, |
98 | }, { | 94 | }, { |
99 | .id = V4L2_CID_CONTRAST, | 95 | .id = V4L2_CID_CONTRAST, |
100 | .type = V4L2_CTRL_TYPE_INTEGER, | 96 | .type = V4L2_CTRL_TYPE_INTEGER, |
101 | .name = "Contrast", | 97 | .name = "Contrast", |
102 | .minimum = 0, | 98 | .minimum = 0, |
103 | .maximum = 255, | 99 | .maximum = 255, |
104 | .step = 0x1, | 100 | .step = 0x1, |
105 | .default_value = 0x10, | 101 | .default_value = 0x10, |
106 | .flags = V4L2_CTRL_FLAG_SLIDER, | 102 | .flags = V4L2_CTRL_FLAG_SLIDER, |
107 | }, { | 103 | }, { |
108 | .id = V4L2_CID_SATURATION, | 104 | .id = V4L2_CID_SATURATION, |
109 | .type = V4L2_CTRL_TYPE_INTEGER, | 105 | .type = V4L2_CTRL_TYPE_INTEGER, |
110 | .name = "Saturation", | 106 | .name = "Saturation", |
111 | .minimum = 0, | 107 | .minimum = 0, |
112 | .maximum = 255, | 108 | .maximum = 255, |
113 | .step = 0x1, | 109 | .step = 0x1, |
114 | .default_value = 127, | 110 | .default_value = 127, |
115 | .flags = V4L2_CTRL_FLAG_SLIDER, | 111 | .flags = V4L2_CTRL_FLAG_SLIDER, |
116 | }, { | 112 | }, { |
117 | .id = V4L2_CID_HUE, | 113 | .id = V4L2_CID_HUE, |
118 | .type = V4L2_CTRL_TYPE_INTEGER, | 114 | .type = V4L2_CTRL_TYPE_INTEGER, |
119 | .name = "Hue", | 115 | .name = "Hue", |
120 | .minimum = -128, | 116 | .minimum = -128, |
121 | .maximum = 127, | 117 | .maximum = 127, |
122 | .step = 0x1, | 118 | .step = 0x1, |
123 | .default_value = 0, | 119 | .default_value = 0, |
124 | .flags = V4L2_CTRL_FLAG_SLIDER, | 120 | .flags = V4L2_CTRL_FLAG_SLIDER, |
125 | } | 121 | } |
126 | }; | 122 | }; |
127 | 123 | ||
128 | #define dprintk(dev, level, fmt, arg...) \ | 124 | #define dprintk(dev, level, fmt, arg...) \ |
129 | v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) | 125 | v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) |
130 | 126 | ||
131 | /* ------------------------------------------------------------------ | 127 | /* ------------------------------------------------------------------ |
132 | Basic structures | 128 | Basic structures |
133 | ------------------------------------------------------------------*/ | 129 | ------------------------------------------------------------------*/ |
134 | 130 | ||
135 | struct vivi_fmt { | 131 | struct vivi_fmt { |
136 | char *name; | 132 | char *name; |
137 | u32 fourcc; /* v4l2 format id */ | 133 | u32 fourcc; /* v4l2 format id */ |
138 | int depth; | 134 | int depth; |
139 | }; | 135 | }; |
140 | 136 | ||
141 | static struct vivi_fmt formats[] = { | 137 | static struct vivi_fmt formats[] = { |
142 | { | 138 | { |
143 | .name = "4:2:2, packed, YUYV", | 139 | .name = "4:2:2, packed, YUYV", |
144 | .fourcc = V4L2_PIX_FMT_YUYV, | 140 | .fourcc = V4L2_PIX_FMT_YUYV, |
145 | .depth = 16, | 141 | .depth = 16, |
146 | }, | 142 | }, |
147 | { | 143 | { |
148 | .name = "4:2:2, packed, UYVY", | 144 | .name = "4:2:2, packed, UYVY", |
149 | .fourcc = V4L2_PIX_FMT_UYVY, | 145 | .fourcc = V4L2_PIX_FMT_UYVY, |
150 | .depth = 16, | 146 | .depth = 16, |
151 | }, | 147 | }, |
152 | { | 148 | { |
153 | .name = "RGB565 (LE)", | 149 | .name = "RGB565 (LE)", |
154 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | 150 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ |
155 | .depth = 16, | 151 | .depth = 16, |
156 | }, | 152 | }, |
157 | { | 153 | { |
158 | .name = "RGB565 (BE)", | 154 | .name = "RGB565 (BE)", |
159 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | 155 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ |
160 | .depth = 16, | 156 | .depth = 16, |
161 | }, | 157 | }, |
162 | { | 158 | { |
163 | .name = "RGB555 (LE)", | 159 | .name = "RGB555 (LE)", |
164 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | 160 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ |
165 | .depth = 16, | 161 | .depth = 16, |
166 | }, | 162 | }, |
167 | { | 163 | { |
168 | .name = "RGB555 (BE)", | 164 | .name = "RGB555 (BE)", |
169 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | 165 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ |
170 | .depth = 16, | 166 | .depth = 16, |
171 | }, | 167 | }, |
172 | }; | 168 | }; |
173 | 169 | ||
174 | static struct vivi_fmt *get_format(struct v4l2_format *f) | 170 | static struct vivi_fmt *get_format(struct v4l2_format *f) |
175 | { | 171 | { |
176 | struct vivi_fmt *fmt; | 172 | struct vivi_fmt *fmt; |
177 | unsigned int k; | 173 | unsigned int k; |
178 | 174 | ||
179 | for (k = 0; k < ARRAY_SIZE(formats); k++) { | 175 | for (k = 0; k < ARRAY_SIZE(formats); k++) { |
180 | fmt = &formats[k]; | 176 | fmt = &formats[k]; |
181 | if (fmt->fourcc == f->fmt.pix.pixelformat) | 177 | if (fmt->fourcc == f->fmt.pix.pixelformat) |
182 | break; | 178 | break; |
183 | } | 179 | } |
184 | 180 | ||
185 | if (k == ARRAY_SIZE(formats)) | 181 | if (k == ARRAY_SIZE(formats)) |
186 | return NULL; | 182 | return NULL; |
187 | 183 | ||
188 | return &formats[k]; | 184 | return &formats[k]; |
189 | } | 185 | } |
190 | 186 | ||
191 | struct sg_to_addr { | 187 | struct sg_to_addr { |
192 | int pos; | 188 | int pos; |
193 | struct scatterlist *sg; | 189 | struct scatterlist *sg; |
194 | }; | 190 | }; |
195 | 191 | ||
196 | /* buffer for one video frame */ | 192 | /* buffer for one video frame */ |
197 | struct vivi_buffer { | 193 | struct vivi_buffer { |
198 | /* common v4l buffer stuff -- must be first */ | 194 | /* common v4l buffer stuff -- must be first */ |
199 | struct videobuf_buffer vb; | 195 | struct videobuf_buffer vb; |
200 | 196 | ||
201 | struct vivi_fmt *fmt; | 197 | struct vivi_fmt *fmt; |
202 | }; | 198 | }; |
203 | 199 | ||
204 | struct vivi_dmaqueue { | 200 | struct vivi_dmaqueue { |
205 | struct list_head active; | 201 | struct list_head active; |
206 | 202 | ||
207 | /* thread for generating video stream*/ | 203 | /* thread for generating video stream*/ |
208 | struct task_struct *kthread; | 204 | struct task_struct *kthread; |
209 | wait_queue_head_t wq; | 205 | wait_queue_head_t wq; |
210 | /* Counters to control fps rate */ | 206 | /* Counters to control fps rate */ |
211 | int frame; | 207 | int frame; |
212 | int ini_jiffies; | 208 | int ini_jiffies; |
213 | }; | 209 | }; |
214 | 210 | ||
215 | static LIST_HEAD(vivi_devlist); | 211 | static LIST_HEAD(vivi_devlist); |
216 | 212 | ||
217 | struct vivi_dev { | 213 | struct vivi_dev { |
218 | struct list_head vivi_devlist; | 214 | struct list_head vivi_devlist; |
219 | struct v4l2_device v4l2_dev; | 215 | struct v4l2_device v4l2_dev; |
220 | 216 | ||
221 | spinlock_t slock; | 217 | spinlock_t slock; |
222 | struct mutex mutex; | 218 | struct mutex mutex; |
223 | 219 | ||
224 | int users; | 220 | int users; |
225 | 221 | ||
226 | /* various device info */ | 222 | /* various device info */ |
227 | struct video_device *vfd; | 223 | struct video_device *vfd; |
228 | 224 | ||
229 | struct vivi_dmaqueue vidq; | 225 | struct vivi_dmaqueue vidq; |
230 | 226 | ||
231 | /* Several counters */ | 227 | /* Several counters */ |
232 | int h, m, s, ms; | 228 | int h, m, s, ms; |
233 | unsigned long jiffies; | 229 | unsigned long jiffies; |
234 | char timestr[13]; | 230 | char timestr[13]; |
235 | 231 | ||
236 | int mv_count; /* Controls bars movement */ | 232 | int mv_count; /* Controls bars movement */ |
237 | 233 | ||
238 | /* Input Number */ | 234 | /* Input Number */ |
239 | int input; | 235 | int input; |
240 | 236 | ||
241 | /* Control 'registers' */ | 237 | /* Control 'registers' */ |
242 | int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; | 238 | int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; |
243 | }; | 239 | }; |
244 | 240 | ||
245 | struct vivi_fh { | 241 | struct vivi_fh { |
246 | struct vivi_dev *dev; | 242 | struct vivi_dev *dev; |
247 | 243 | ||
248 | /* video capture */ | 244 | /* video capture */ |
249 | struct vivi_fmt *fmt; | 245 | struct vivi_fmt *fmt; |
250 | unsigned int width, height; | 246 | unsigned int width, height; |
251 | struct videobuf_queue vb_vidq; | 247 | struct videobuf_queue vb_vidq; |
252 | 248 | ||
253 | enum v4l2_buf_type type; | 249 | enum v4l2_buf_type type; |
254 | unsigned char bars[8][3]; | 250 | unsigned char bars[8][3]; |
255 | int input; /* Input Number on bars */ | 251 | int input; /* Input Number on bars */ |
256 | }; | 252 | }; |
257 | 253 | ||
258 | /* ------------------------------------------------------------------ | 254 | /* ------------------------------------------------------------------ |
259 | DMA and thread functions | 255 | DMA and thread functions |
260 | ------------------------------------------------------------------*/ | 256 | ------------------------------------------------------------------*/ |
261 | 257 | ||
262 | /* Bars and Colors should match positions */ | 258 | /* Bars and Colors should match positions */ |
263 | 259 | ||
264 | enum colors { | 260 | enum colors { |
265 | WHITE, | 261 | WHITE, |
266 | AMBAR, | 262 | AMBAR, |
267 | CYAN, | 263 | CYAN, |
268 | GREEN, | 264 | GREEN, |
269 | MAGENTA, | 265 | MAGENTA, |
270 | RED, | 266 | RED, |
271 | BLUE, | 267 | BLUE, |
272 | BLACK, | 268 | BLACK, |
273 | }; | 269 | }; |
274 | 270 | ||
275 | /* R G B */ | 271 | /* R G B */ |
276 | #define COLOR_WHITE {204, 204, 204} | 272 | #define COLOR_WHITE {204, 204, 204} |
277 | #define COLOR_AMBAR {208, 208, 0} | 273 | #define COLOR_AMBAR {208, 208, 0} |
278 | #define COLOR_CIAN { 0, 206, 206} | 274 | #define COLOR_CIAN { 0, 206, 206} |
279 | #define COLOR_GREEN { 0, 239, 0} | 275 | #define COLOR_GREEN { 0, 239, 0} |
280 | #define COLOR_MAGENTA {239, 0, 239} | 276 | #define COLOR_MAGENTA {239, 0, 239} |
281 | #define COLOR_RED {205, 0, 0} | 277 | #define COLOR_RED {205, 0, 0} |
282 | #define COLOR_BLUE { 0, 0, 255} | 278 | #define COLOR_BLUE { 0, 0, 255} |
283 | #define COLOR_BLACK { 0, 0, 0} | 279 | #define COLOR_BLACK { 0, 0, 0} |
284 | 280 | ||
285 | struct bar_std { | 281 | struct bar_std { |
286 | u8 bar[8][3]; | 282 | u8 bar[8][3]; |
287 | }; | 283 | }; |
288 | 284 | ||
289 | /* Maximum number of bars are 10 - otherwise, the input print code | 285 | /* Maximum number of bars are 10 - otherwise, the input print code |
290 | should be modified */ | 286 | should be modified */ |
291 | static struct bar_std bars[] = { | 287 | static struct bar_std bars[] = { |
292 | { /* Standard ITU-R color bar sequence */ | 288 | { /* Standard ITU-R color bar sequence */ |
293 | { | 289 | { |
294 | COLOR_WHITE, | 290 | COLOR_WHITE, |
295 | COLOR_AMBAR, | 291 | COLOR_AMBAR, |
296 | COLOR_CIAN, | 292 | COLOR_CIAN, |
297 | COLOR_GREEN, | 293 | COLOR_GREEN, |
298 | COLOR_MAGENTA, | 294 | COLOR_MAGENTA, |
299 | COLOR_RED, | 295 | COLOR_RED, |
300 | COLOR_BLUE, | 296 | COLOR_BLUE, |
301 | COLOR_BLACK, | 297 | COLOR_BLACK, |
302 | } | 298 | } |
303 | }, { | 299 | }, { |
304 | { | 300 | { |
305 | COLOR_WHITE, | 301 | COLOR_WHITE, |
306 | COLOR_AMBAR, | 302 | COLOR_AMBAR, |
307 | COLOR_BLACK, | 303 | COLOR_BLACK, |
308 | COLOR_WHITE, | 304 | COLOR_WHITE, |
309 | COLOR_AMBAR, | 305 | COLOR_AMBAR, |
310 | COLOR_BLACK, | 306 | COLOR_BLACK, |
311 | COLOR_WHITE, | 307 | COLOR_WHITE, |
312 | COLOR_AMBAR, | 308 | COLOR_AMBAR, |
313 | } | 309 | } |
314 | }, { | 310 | }, { |
315 | { | 311 | { |
316 | COLOR_WHITE, | 312 | COLOR_WHITE, |
317 | COLOR_CIAN, | 313 | COLOR_CIAN, |
318 | COLOR_BLACK, | 314 | COLOR_BLACK, |
319 | COLOR_WHITE, | 315 | COLOR_WHITE, |
320 | COLOR_CIAN, | 316 | COLOR_CIAN, |
321 | COLOR_BLACK, | 317 | COLOR_BLACK, |
322 | COLOR_WHITE, | 318 | COLOR_WHITE, |
323 | COLOR_CIAN, | 319 | COLOR_CIAN, |
324 | } | 320 | } |
325 | }, { | 321 | }, { |
326 | { | 322 | { |
327 | COLOR_WHITE, | 323 | COLOR_WHITE, |
328 | COLOR_GREEN, | 324 | COLOR_GREEN, |
329 | COLOR_BLACK, | 325 | COLOR_BLACK, |
330 | COLOR_WHITE, | 326 | COLOR_WHITE, |
331 | COLOR_GREEN, | 327 | COLOR_GREEN, |
332 | COLOR_BLACK, | 328 | COLOR_BLACK, |
333 | COLOR_WHITE, | 329 | COLOR_WHITE, |
334 | COLOR_GREEN, | 330 | COLOR_GREEN, |
335 | } | 331 | } |
336 | }, | 332 | }, |
337 | }; | 333 | }; |
338 | 334 | ||
339 | #define NUM_INPUTS ARRAY_SIZE(bars) | 335 | #define NUM_INPUTS ARRAY_SIZE(bars) |
340 | 336 | ||
341 | #define TO_Y(r, g, b) \ | 337 | #define TO_Y(r, g, b) \ |
342 | (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) | 338 | (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) |
343 | /* RGB to V(Cr) Color transform */ | 339 | /* RGB to V(Cr) Color transform */ |
344 | #define TO_V(r, g, b) \ | 340 | #define TO_V(r, g, b) \ |
345 | (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) | 341 | (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) |
346 | /* RGB to U(Cb) Color transform */ | 342 | /* RGB to U(Cb) Color transform */ |
347 | #define TO_U(r, g, b) \ | 343 | #define TO_U(r, g, b) \ |
348 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) | 344 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) |
349 | 345 | ||
350 | #define TSTAMP_MIN_Y 24 | 346 | #define TSTAMP_MIN_Y 24 |
351 | #define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) | 347 | #define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) |
352 | #define TSTAMP_INPUT_X 10 | 348 | #define TSTAMP_INPUT_X 10 |
353 | #define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) | 349 | #define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) |
354 | 350 | ||
355 | static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos) | 351 | static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos) |
356 | { | 352 | { |
357 | unsigned char r_y, g_u, b_v; | 353 | unsigned char r_y, g_u, b_v; |
358 | unsigned char *p; | 354 | unsigned char *p; |
359 | int color; | 355 | int color; |
360 | 356 | ||
361 | r_y = fh->bars[colorpos][0]; /* R or precalculated Y */ | 357 | r_y = fh->bars[colorpos][0]; /* R or precalculated Y */ |
362 | g_u = fh->bars[colorpos][1]; /* G or precalculated U */ | 358 | g_u = fh->bars[colorpos][1]; /* G or precalculated U */ |
363 | b_v = fh->bars[colorpos][2]; /* B or precalculated V */ | 359 | b_v = fh->bars[colorpos][2]; /* B or precalculated V */ |
364 | 360 | ||
365 | for (color = 0; color < 4; color++) { | 361 | for (color = 0; color < 4; color++) { |
366 | p = buf + color; | 362 | p = buf + color; |
367 | 363 | ||
368 | switch (fh->fmt->fourcc) { | 364 | switch (fh->fmt->fourcc) { |
369 | case V4L2_PIX_FMT_YUYV: | 365 | case V4L2_PIX_FMT_YUYV: |
370 | switch (color) { | 366 | switch (color) { |
371 | case 0: | 367 | case 0: |
372 | case 2: | 368 | case 2: |
373 | *p = r_y; | 369 | *p = r_y; |
374 | break; | 370 | break; |
375 | case 1: | 371 | case 1: |
376 | *p = g_u; | 372 | *p = g_u; |
377 | break; | 373 | break; |
378 | case 3: | 374 | case 3: |
379 | *p = b_v; | 375 | *p = b_v; |
380 | break; | 376 | break; |
381 | } | 377 | } |
382 | break; | 378 | break; |
383 | case V4L2_PIX_FMT_UYVY: | 379 | case V4L2_PIX_FMT_UYVY: |
384 | switch (color) { | 380 | switch (color) { |
385 | case 1: | 381 | case 1: |
386 | case 3: | 382 | case 3: |
387 | *p = r_y; | 383 | *p = r_y; |
388 | break; | 384 | break; |
389 | case 0: | 385 | case 0: |
390 | *p = g_u; | 386 | *p = g_u; |
391 | break; | 387 | break; |
392 | case 2: | 388 | case 2: |
393 | *p = b_v; | 389 | *p = b_v; |
394 | break; | 390 | break; |
395 | } | 391 | } |
396 | break; | 392 | break; |
397 | case V4L2_PIX_FMT_RGB565: | 393 | case V4L2_PIX_FMT_RGB565: |
398 | switch (color) { | 394 | switch (color) { |
399 | case 0: | 395 | case 0: |
400 | case 2: | 396 | case 2: |
401 | *p = (g_u << 5) | b_v; | 397 | *p = (g_u << 5) | b_v; |
402 | break; | 398 | break; |
403 | case 1: | 399 | case 1: |
404 | case 3: | 400 | case 3: |
405 | *p = (r_y << 3) | (g_u >> 3); | 401 | *p = (r_y << 3) | (g_u >> 3); |
406 | break; | 402 | break; |
407 | } | 403 | } |
408 | break; | 404 | break; |
409 | case V4L2_PIX_FMT_RGB565X: | 405 | case V4L2_PIX_FMT_RGB565X: |
410 | switch (color) { | 406 | switch (color) { |
411 | case 0: | 407 | case 0: |
412 | case 2: | 408 | case 2: |
413 | *p = (r_y << 3) | (g_u >> 3); | 409 | *p = (r_y << 3) | (g_u >> 3); |
414 | break; | 410 | break; |
415 | case 1: | 411 | case 1: |
416 | case 3: | 412 | case 3: |
417 | *p = (g_u << 5) | b_v; | 413 | *p = (g_u << 5) | b_v; |
418 | break; | 414 | break; |
419 | } | 415 | } |
420 | break; | 416 | break; |
421 | case V4L2_PIX_FMT_RGB555: | 417 | case V4L2_PIX_FMT_RGB555: |
422 | switch (color) { | 418 | switch (color) { |
423 | case 0: | 419 | case 0: |
424 | case 2: | 420 | case 2: |
425 | *p = (g_u << 5) | b_v; | 421 | *p = (g_u << 5) | b_v; |
426 | break; | 422 | break; |
427 | case 1: | 423 | case 1: |
428 | case 3: | 424 | case 3: |
429 | *p = (r_y << 2) | (g_u >> 3); | 425 | *p = (r_y << 2) | (g_u >> 3); |
430 | break; | 426 | break; |
431 | } | 427 | } |
432 | break; | 428 | break; |
433 | case V4L2_PIX_FMT_RGB555X: | 429 | case V4L2_PIX_FMT_RGB555X: |
434 | switch (color) { | 430 | switch (color) { |
435 | case 0: | 431 | case 0: |
436 | case 2: | 432 | case 2: |
437 | *p = (r_y << 2) | (g_u >> 3); | 433 | *p = (r_y << 2) | (g_u >> 3); |
438 | break; | 434 | break; |
439 | case 1: | 435 | case 1: |
440 | case 3: | 436 | case 3: |
441 | *p = (g_u << 5) | b_v; | 437 | *p = (g_u << 5) | b_v; |
442 | break; | 438 | break; |
443 | } | 439 | } |
444 | break; | 440 | break; |
445 | } | 441 | } |
446 | } | 442 | } |
447 | } | 443 | } |
448 | 444 | ||
449 | static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax, | 445 | static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax, |
450 | int hmax, int line, int count, char *timestr) | 446 | int hmax, int line, int count, char *timestr) |
451 | { | 447 | { |
452 | int w, i, j; | 448 | int w, i, j; |
453 | int pos = inipos; | 449 | int pos = inipos; |
454 | char *s; | 450 | char *s; |
455 | u8 chr; | 451 | u8 chr; |
456 | 452 | ||
457 | /* We will just duplicate the second pixel at the packet */ | 453 | /* We will just duplicate the second pixel at the packet */ |
458 | wmax /= 2; | 454 | wmax /= 2; |
459 | 455 | ||
460 | /* Generate a standard color bar pattern */ | 456 | /* Generate a standard color bar pattern */ |
461 | for (w = 0; w < wmax; w++) { | 457 | for (w = 0; w < wmax; w++) { |
462 | int colorpos = ((w + count) * 8/(wmax + 1)) % 8; | 458 | int colorpos = ((w + count) * 8/(wmax + 1)) % 8; |
463 | 459 | ||
464 | gen_twopix(fh, basep + pos, colorpos); | 460 | gen_twopix(fh, basep + pos, colorpos); |
465 | pos += 4; /* only 16 bpp supported for now */ | 461 | pos += 4; /* only 16 bpp supported for now */ |
466 | } | 462 | } |
467 | 463 | ||
468 | /* Prints input entry number */ | 464 | /* Prints input entry number */ |
469 | 465 | ||
470 | /* Checks if it is possible to input number */ | 466 | /* Checks if it is possible to input number */ |
471 | if (TSTAMP_MAX_Y >= hmax) | 467 | if (TSTAMP_MAX_Y >= hmax) |
472 | goto end; | 468 | goto end; |
473 | 469 | ||
474 | if (TSTAMP_INPUT_X + strlen(timestr) >= wmax) | 470 | if (TSTAMP_INPUT_X + strlen(timestr) >= wmax) |
475 | goto end; | 471 | goto end; |
476 | 472 | ||
477 | if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { | 473 | if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { |
478 | chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y]; | 474 | chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y]; |
479 | pos = TSTAMP_INPUT_X; | 475 | pos = TSTAMP_INPUT_X; |
480 | for (i = 0; i < 7; i++) { | 476 | for (i = 0; i < 7; i++) { |
481 | /* Draw white font on black background */ | 477 | /* Draw white font on black background */ |
482 | if (chr & 1 << (7 - i)) | 478 | if (chr & 1 << (7 - i)) |
483 | gen_twopix(fh, basep + pos, WHITE); | 479 | gen_twopix(fh, basep + pos, WHITE); |
484 | else | 480 | else |
485 | gen_twopix(fh, basep + pos, BLACK); | 481 | gen_twopix(fh, basep + pos, BLACK); |
486 | pos += 2; | 482 | pos += 2; |
487 | } | 483 | } |
488 | } | 484 | } |
489 | 485 | ||
490 | /* Checks if it is possible to show timestamp */ | 486 | /* Checks if it is possible to show timestamp */ |
491 | if (TSTAMP_MIN_X + strlen(timestr) >= wmax) | 487 | if (TSTAMP_MIN_X + strlen(timestr) >= wmax) |
492 | goto end; | 488 | goto end; |
493 | 489 | ||
494 | /* Print stream time */ | 490 | /* Print stream time */ |
495 | if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { | 491 | if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { |
496 | j = TSTAMP_MIN_X; | 492 | j = TSTAMP_MIN_X; |
497 | for (s = timestr; *s; s++) { | 493 | for (s = timestr; *s; s++) { |
498 | chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; | 494 | chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; |
499 | for (i = 0; i < 7; i++) { | 495 | for (i = 0; i < 7; i++) { |
500 | pos = inipos + j * 2; | 496 | pos = inipos + j * 2; |
501 | /* Draw white font on black background */ | 497 | /* Draw white font on black background */ |
502 | if (chr & 1 << (7 - i)) | 498 | if (chr & 1 << (7 - i)) |
503 | gen_twopix(fh, basep + pos, WHITE); | 499 | gen_twopix(fh, basep + pos, WHITE); |
504 | else | 500 | else |
505 | gen_twopix(fh, basep + pos, BLACK); | 501 | gen_twopix(fh, basep + pos, BLACK); |
506 | j++; | 502 | j++; |
507 | } | 503 | } |
508 | } | 504 | } |
509 | } | 505 | } |
510 | 506 | ||
511 | end: | 507 | end: |
512 | return; | 508 | return; |
513 | } | 509 | } |
514 | 510 | ||
515 | static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf) | 511 | static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf) |
516 | { | 512 | { |
517 | struct vivi_dev *dev = fh->dev; | 513 | struct vivi_dev *dev = fh->dev; |
518 | int h , pos = 0; | 514 | int h , pos = 0; |
519 | int hmax = buf->vb.height; | 515 | int hmax = buf->vb.height; |
520 | int wmax = buf->vb.width; | 516 | int wmax = buf->vb.width; |
521 | struct timeval ts; | 517 | struct timeval ts; |
522 | char *tmpbuf; | 518 | char *tmpbuf; |
523 | void *vbuf = videobuf_to_vmalloc(&buf->vb); | 519 | void *vbuf = videobuf_to_vmalloc(&buf->vb); |
524 | 520 | ||
525 | if (!vbuf) | 521 | if (!vbuf) |
526 | return; | 522 | return; |
527 | 523 | ||
528 | tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC); | 524 | tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC); |
529 | if (!tmpbuf) | 525 | if (!tmpbuf) |
530 | return; | 526 | return; |
531 | 527 | ||
532 | for (h = 0; h < hmax; h++) { | 528 | for (h = 0; h < hmax; h++) { |
533 | gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count, | 529 | gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count, |
534 | dev->timestr); | 530 | dev->timestr); |
535 | memcpy(vbuf + pos, tmpbuf, wmax * 2); | 531 | memcpy(vbuf + pos, tmpbuf, wmax * 2); |
536 | pos += wmax*2; | 532 | pos += wmax*2; |
537 | } | 533 | } |
538 | 534 | ||
539 | dev->mv_count++; | 535 | dev->mv_count++; |
540 | 536 | ||
541 | kfree(tmpbuf); | 537 | kfree(tmpbuf); |
542 | 538 | ||
543 | /* Updates stream time */ | 539 | /* Updates stream time */ |
544 | 540 | ||
545 | dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); | 541 | dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); |
546 | dev->jiffies = jiffies; | 542 | dev->jiffies = jiffies; |
547 | if (dev->ms >= 1000) { | 543 | if (dev->ms >= 1000) { |
548 | dev->ms -= 1000; | 544 | dev->ms -= 1000; |
549 | dev->s++; | 545 | dev->s++; |
550 | if (dev->s >= 60) { | 546 | if (dev->s >= 60) { |
551 | dev->s -= 60; | 547 | dev->s -= 60; |
552 | dev->m++; | 548 | dev->m++; |
553 | if (dev->m > 60) { | 549 | if (dev->m > 60) { |
554 | dev->m -= 60; | 550 | dev->m -= 60; |
555 | dev->h++; | 551 | dev->h++; |
556 | if (dev->h > 24) | 552 | if (dev->h > 24) |
557 | dev->h -= 24; | 553 | dev->h -= 24; |
558 | } | 554 | } |
559 | } | 555 | } |
560 | } | 556 | } |
561 | sprintf(dev->timestr, "%02d:%02d:%02d:%03d", | 557 | sprintf(dev->timestr, "%02d:%02d:%02d:%03d", |
562 | dev->h, dev->m, dev->s, dev->ms); | 558 | dev->h, dev->m, dev->s, dev->ms); |
563 | 559 | ||
564 | dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", | 560 | dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", |
565 | dev->timestr, (unsigned long)tmpbuf, pos); | 561 | dev->timestr, (unsigned long)tmpbuf, pos); |
566 | 562 | ||
567 | /* Advice that buffer was filled */ | 563 | /* Advice that buffer was filled */ |
568 | buf->vb.field_count++; | 564 | buf->vb.field_count++; |
569 | do_gettimeofday(&ts); | 565 | do_gettimeofday(&ts); |
570 | buf->vb.ts = ts; | 566 | buf->vb.ts = ts; |
571 | buf->vb.state = VIDEOBUF_DONE; | 567 | buf->vb.state = VIDEOBUF_DONE; |
572 | } | 568 | } |
573 | 569 | ||
574 | static void vivi_thread_tick(struct vivi_fh *fh) | 570 | static void vivi_thread_tick(struct vivi_fh *fh) |
575 | { | 571 | { |
576 | struct vivi_buffer *buf; | 572 | struct vivi_buffer *buf; |
577 | struct vivi_dev *dev = fh->dev; | 573 | struct vivi_dev *dev = fh->dev; |
578 | struct vivi_dmaqueue *dma_q = &dev->vidq; | 574 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
579 | 575 | ||
580 | unsigned long flags = 0; | 576 | unsigned long flags = 0; |
581 | 577 | ||
582 | dprintk(dev, 1, "Thread tick\n"); | 578 | dprintk(dev, 1, "Thread tick\n"); |
583 | 579 | ||
584 | spin_lock_irqsave(&dev->slock, flags); | 580 | spin_lock_irqsave(&dev->slock, flags); |
585 | if (list_empty(&dma_q->active)) { | 581 | if (list_empty(&dma_q->active)) { |
586 | dprintk(dev, 1, "No active queue to serve\n"); | 582 | dprintk(dev, 1, "No active queue to serve\n"); |
587 | goto unlock; | 583 | goto unlock; |
588 | } | 584 | } |
589 | 585 | ||
590 | buf = list_entry(dma_q->active.next, | 586 | buf = list_entry(dma_q->active.next, |
591 | struct vivi_buffer, vb.queue); | 587 | struct vivi_buffer, vb.queue); |
592 | 588 | ||
593 | /* Nobody is waiting on this buffer, return */ | 589 | /* Nobody is waiting on this buffer, return */ |
594 | if (!waitqueue_active(&buf->vb.done)) | 590 | if (!waitqueue_active(&buf->vb.done)) |
595 | goto unlock; | 591 | goto unlock; |
596 | 592 | ||
597 | list_del(&buf->vb.queue); | 593 | list_del(&buf->vb.queue); |
598 | 594 | ||
599 | do_gettimeofday(&buf->vb.ts); | 595 | do_gettimeofday(&buf->vb.ts); |
600 | 596 | ||
601 | /* Fill buffer */ | 597 | /* Fill buffer */ |
602 | vivi_fillbuff(fh, buf); | 598 | vivi_fillbuff(fh, buf); |
603 | dprintk(dev, 1, "filled buffer %p\n", buf); | 599 | dprintk(dev, 1, "filled buffer %p\n", buf); |
604 | 600 | ||
605 | wake_up(&buf->vb.done); | 601 | wake_up(&buf->vb.done); |
606 | dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); | 602 | dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); |
607 | unlock: | 603 | unlock: |
608 | spin_unlock_irqrestore(&dev->slock, flags); | 604 | spin_unlock_irqrestore(&dev->slock, flags); |
609 | return; | 605 | return; |
610 | } | 606 | } |
611 | 607 | ||
612 | #define frames_to_ms(frames) \ | 608 | #define frames_to_ms(frames) \ |
613 | ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) | 609 | ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) |
614 | 610 | ||
615 | static void vivi_sleep(struct vivi_fh *fh) | 611 | static void vivi_sleep(struct vivi_fh *fh) |
616 | { | 612 | { |
617 | struct vivi_dev *dev = fh->dev; | 613 | struct vivi_dev *dev = fh->dev; |
618 | struct vivi_dmaqueue *dma_q = &dev->vidq; | 614 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
619 | int timeout; | 615 | int timeout; |
620 | DECLARE_WAITQUEUE(wait, current); | 616 | DECLARE_WAITQUEUE(wait, current); |
621 | 617 | ||
622 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, | 618 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, |
623 | (unsigned long)dma_q); | 619 | (unsigned long)dma_q); |
624 | 620 | ||
625 | add_wait_queue(&dma_q->wq, &wait); | 621 | add_wait_queue(&dma_q->wq, &wait); |
626 | if (kthread_should_stop()) | 622 | if (kthread_should_stop()) |
627 | goto stop_task; | 623 | goto stop_task; |
628 | 624 | ||
629 | /* Calculate time to wake up */ | 625 | /* Calculate time to wake up */ |
630 | timeout = msecs_to_jiffies(frames_to_ms(1)); | 626 | timeout = msecs_to_jiffies(frames_to_ms(1)); |
631 | 627 | ||
632 | vivi_thread_tick(fh); | 628 | vivi_thread_tick(fh); |
633 | 629 | ||
634 | schedule_timeout_interruptible(timeout); | 630 | schedule_timeout_interruptible(timeout); |
635 | 631 | ||
636 | stop_task: | 632 | stop_task: |
637 | remove_wait_queue(&dma_q->wq, &wait); | 633 | remove_wait_queue(&dma_q->wq, &wait); |
638 | try_to_freeze(); | 634 | try_to_freeze(); |
639 | } | 635 | } |
640 | 636 | ||
641 | static int vivi_thread(void *data) | 637 | static int vivi_thread(void *data) |
642 | { | 638 | { |
643 | struct vivi_fh *fh = data; | 639 | struct vivi_fh *fh = data; |
644 | struct vivi_dev *dev = fh->dev; | 640 | struct vivi_dev *dev = fh->dev; |
645 | 641 | ||
646 | dprintk(dev, 1, "thread started\n"); | 642 | dprintk(dev, 1, "thread started\n"); |
647 | 643 | ||
648 | set_freezable(); | 644 | set_freezable(); |
649 | 645 | ||
650 | for (;;) { | 646 | for (;;) { |
651 | vivi_sleep(fh); | 647 | vivi_sleep(fh); |
652 | 648 | ||
653 | if (kthread_should_stop()) | 649 | if (kthread_should_stop()) |
654 | break; | 650 | break; |
655 | } | 651 | } |
656 | dprintk(dev, 1, "thread: exit\n"); | 652 | dprintk(dev, 1, "thread: exit\n"); |
657 | return 0; | 653 | return 0; |
658 | } | 654 | } |
659 | 655 | ||
660 | static int vivi_start_thread(struct vivi_fh *fh) | 656 | static int vivi_start_thread(struct vivi_fh *fh) |
661 | { | 657 | { |
662 | struct vivi_dev *dev = fh->dev; | 658 | struct vivi_dev *dev = fh->dev; |
663 | struct vivi_dmaqueue *dma_q = &dev->vidq; | 659 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
664 | 660 | ||
665 | dma_q->frame = 0; | 661 | dma_q->frame = 0; |
666 | dma_q->ini_jiffies = jiffies; | 662 | dma_q->ini_jiffies = jiffies; |
667 | 663 | ||
668 | dprintk(dev, 1, "%s\n", __func__); | 664 | dprintk(dev, 1, "%s\n", __func__); |
669 | 665 | ||
670 | dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); | 666 | dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); |
671 | 667 | ||
672 | if (IS_ERR(dma_q->kthread)) { | 668 | if (IS_ERR(dma_q->kthread)) { |
673 | v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); | 669 | v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); |
674 | return PTR_ERR(dma_q->kthread); | 670 | return PTR_ERR(dma_q->kthread); |
675 | } | 671 | } |
676 | /* Wakes thread */ | 672 | /* Wakes thread */ |
677 | wake_up_interruptible(&dma_q->wq); | 673 | wake_up_interruptible(&dma_q->wq); |
678 | 674 | ||
679 | dprintk(dev, 1, "returning from %s\n", __func__); | 675 | dprintk(dev, 1, "returning from %s\n", __func__); |
680 | return 0; | 676 | return 0; |
681 | } | 677 | } |
682 | 678 | ||
683 | static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) | 679 | static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) |
684 | { | 680 | { |
685 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | 681 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); |
686 | 682 | ||
687 | dprintk(dev, 1, "%s\n", __func__); | 683 | dprintk(dev, 1, "%s\n", __func__); |
688 | /* shutdown control thread */ | 684 | /* shutdown control thread */ |
689 | if (dma_q->kthread) { | 685 | if (dma_q->kthread) { |
690 | kthread_stop(dma_q->kthread); | 686 | kthread_stop(dma_q->kthread); |
691 | dma_q->kthread = NULL; | 687 | dma_q->kthread = NULL; |
692 | } | 688 | } |
693 | } | 689 | } |
694 | 690 | ||
695 | /* ------------------------------------------------------------------ | 691 | /* ------------------------------------------------------------------ |
696 | Videobuf operations | 692 | Videobuf operations |
697 | ------------------------------------------------------------------*/ | 693 | ------------------------------------------------------------------*/ |
698 | static int | 694 | static int |
699 | buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) | 695 | buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) |
700 | { | 696 | { |
701 | struct vivi_fh *fh = vq->priv_data; | 697 | struct vivi_fh *fh = vq->priv_data; |
702 | struct vivi_dev *dev = fh->dev; | 698 | struct vivi_dev *dev = fh->dev; |
703 | 699 | ||
704 | *size = fh->width*fh->height*2; | 700 | *size = fh->width*fh->height*2; |
705 | 701 | ||
706 | if (0 == *count) | 702 | if (0 == *count) |
707 | *count = 32; | 703 | *count = 32; |
708 | 704 | ||
709 | while (*size * *count > vid_limit * 1024 * 1024) | 705 | while (*size * *count > vid_limit * 1024 * 1024) |
710 | (*count)--; | 706 | (*count)--; |
711 | 707 | ||
712 | dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, | 708 | dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, |
713 | *count, *size); | 709 | *count, *size); |
714 | 710 | ||
715 | return 0; | 711 | return 0; |
716 | } | 712 | } |
717 | 713 | ||
718 | static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) | 714 | static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) |
719 | { | 715 | { |
720 | struct vivi_fh *fh = vq->priv_data; | 716 | struct vivi_fh *fh = vq->priv_data; |
721 | struct vivi_dev *dev = fh->dev; | 717 | struct vivi_dev *dev = fh->dev; |
722 | 718 | ||
723 | dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); | 719 | dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); |
724 | 720 | ||
725 | if (in_interrupt()) | 721 | if (in_interrupt()) |
726 | BUG(); | 722 | BUG(); |
727 | 723 | ||
728 | videobuf_vmalloc_free(&buf->vb); | 724 | videobuf_vmalloc_free(&buf->vb); |
729 | dprintk(dev, 1, "free_buffer: freed\n"); | 725 | dprintk(dev, 1, "free_buffer: freed\n"); |
730 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | 726 | buf->vb.state = VIDEOBUF_NEEDS_INIT; |
731 | } | 727 | } |
732 | 728 | ||
733 | #define norm_maxw() 1024 | 729 | #define norm_maxw() 1024 |
734 | #define norm_maxh() 768 | 730 | #define norm_maxh() 768 |
735 | static int | 731 | static int |
736 | buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | 732 | buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, |
737 | enum v4l2_field field) | 733 | enum v4l2_field field) |
738 | { | 734 | { |
739 | struct vivi_fh *fh = vq->priv_data; | 735 | struct vivi_fh *fh = vq->priv_data; |
740 | struct vivi_dev *dev = fh->dev; | 736 | struct vivi_dev *dev = fh->dev; |
741 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 737 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
742 | int rc; | 738 | int rc; |
743 | 739 | ||
744 | dprintk(dev, 1, "%s, field=%d\n", __func__, field); | 740 | dprintk(dev, 1, "%s, field=%d\n", __func__, field); |
745 | 741 | ||
746 | BUG_ON(NULL == fh->fmt); | 742 | BUG_ON(NULL == fh->fmt); |
747 | 743 | ||
748 | if (fh->width < 48 || fh->width > norm_maxw() || | 744 | if (fh->width < 48 || fh->width > norm_maxw() || |
749 | fh->height < 32 || fh->height > norm_maxh()) | 745 | fh->height < 32 || fh->height > norm_maxh()) |
750 | return -EINVAL; | 746 | return -EINVAL; |
751 | 747 | ||
752 | buf->vb.size = fh->width*fh->height*2; | 748 | buf->vb.size = fh->width*fh->height*2; |
753 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | 749 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) |
754 | return -EINVAL; | 750 | return -EINVAL; |
755 | 751 | ||
756 | /* These properties only change when queue is idle, see s_fmt */ | 752 | /* These properties only change when queue is idle, see s_fmt */ |
757 | buf->fmt = fh->fmt; | 753 | buf->fmt = fh->fmt; |
758 | buf->vb.width = fh->width; | 754 | buf->vb.width = fh->width; |
759 | buf->vb.height = fh->height; | 755 | buf->vb.height = fh->height; |
760 | buf->vb.field = field; | 756 | buf->vb.field = field; |
761 | 757 | ||
762 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 758 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
763 | rc = videobuf_iolock(vq, &buf->vb, NULL); | 759 | rc = videobuf_iolock(vq, &buf->vb, NULL); |
764 | if (rc < 0) | 760 | if (rc < 0) |
765 | goto fail; | 761 | goto fail; |
766 | } | 762 | } |
767 | 763 | ||
768 | buf->vb.state = VIDEOBUF_PREPARED; | 764 | buf->vb.state = VIDEOBUF_PREPARED; |
769 | 765 | ||
770 | return 0; | 766 | return 0; |
771 | 767 | ||
772 | fail: | 768 | fail: |
773 | free_buffer(vq, buf); | 769 | free_buffer(vq, buf); |
774 | return rc; | 770 | return rc; |
775 | } | 771 | } |
776 | 772 | ||
777 | static void | 773 | static void |
778 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | 774 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) |
779 | { | 775 | { |
780 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 776 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
781 | struct vivi_fh *fh = vq->priv_data; | 777 | struct vivi_fh *fh = vq->priv_data; |
782 | struct vivi_dev *dev = fh->dev; | 778 | struct vivi_dev *dev = fh->dev; |
783 | struct vivi_dmaqueue *vidq = &dev->vidq; | 779 | struct vivi_dmaqueue *vidq = &dev->vidq; |
784 | 780 | ||
785 | dprintk(dev, 1, "%s\n", __func__); | 781 | dprintk(dev, 1, "%s\n", __func__); |
786 | 782 | ||
787 | buf->vb.state = VIDEOBUF_QUEUED; | 783 | buf->vb.state = VIDEOBUF_QUEUED; |
788 | list_add_tail(&buf->vb.queue, &vidq->active); | 784 | list_add_tail(&buf->vb.queue, &vidq->active); |
789 | } | 785 | } |
790 | 786 | ||
791 | static void buffer_release(struct videobuf_queue *vq, | 787 | static void buffer_release(struct videobuf_queue *vq, |
792 | struct videobuf_buffer *vb) | 788 | struct videobuf_buffer *vb) |
793 | { | 789 | { |
794 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 790 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
795 | struct vivi_fh *fh = vq->priv_data; | 791 | struct vivi_fh *fh = vq->priv_data; |
796 | struct vivi_dev *dev = (struct vivi_dev *)fh->dev; | 792 | struct vivi_dev *dev = (struct vivi_dev *)fh->dev; |
797 | 793 | ||
798 | dprintk(dev, 1, "%s\n", __func__); | 794 | dprintk(dev, 1, "%s\n", __func__); |
799 | 795 | ||
800 | free_buffer(vq, buf); | 796 | free_buffer(vq, buf); |
801 | } | 797 | } |
802 | 798 | ||
803 | static struct videobuf_queue_ops vivi_video_qops = { | 799 | static struct videobuf_queue_ops vivi_video_qops = { |
804 | .buf_setup = buffer_setup, | 800 | .buf_setup = buffer_setup, |
805 | .buf_prepare = buffer_prepare, | 801 | .buf_prepare = buffer_prepare, |
806 | .buf_queue = buffer_queue, | 802 | .buf_queue = buffer_queue, |
807 | .buf_release = buffer_release, | 803 | .buf_release = buffer_release, |
808 | }; | 804 | }; |
809 | 805 | ||
810 | /* ------------------------------------------------------------------ | 806 | /* ------------------------------------------------------------------ |
811 | IOCTL vidioc handling | 807 | IOCTL vidioc handling |
812 | ------------------------------------------------------------------*/ | 808 | ------------------------------------------------------------------*/ |
813 | static int vidioc_querycap(struct file *file, void *priv, | 809 | static int vidioc_querycap(struct file *file, void *priv, |
814 | struct v4l2_capability *cap) | 810 | struct v4l2_capability *cap) |
815 | { | 811 | { |
816 | struct vivi_fh *fh = priv; | 812 | struct vivi_fh *fh = priv; |
817 | struct vivi_dev *dev = fh->dev; | 813 | struct vivi_dev *dev = fh->dev; |
818 | 814 | ||
819 | strcpy(cap->driver, "vivi"); | 815 | strcpy(cap->driver, "vivi"); |
820 | strcpy(cap->card, "vivi"); | 816 | strcpy(cap->card, "vivi"); |
821 | strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); | 817 | strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); |
822 | cap->version = VIVI_VERSION; | 818 | cap->version = VIVI_VERSION; |
823 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | 819 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | |
824 | V4L2_CAP_STREAMING | | 820 | V4L2_CAP_STREAMING | |
825 | V4L2_CAP_READWRITE; | 821 | V4L2_CAP_READWRITE; |
826 | return 0; | 822 | return 0; |
827 | } | 823 | } |
828 | 824 | ||
829 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | 825 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
830 | struct v4l2_fmtdesc *f) | 826 | struct v4l2_fmtdesc *f) |
831 | { | 827 | { |
832 | struct vivi_fmt *fmt; | 828 | struct vivi_fmt *fmt; |
833 | 829 | ||
834 | if (f->index >= ARRAY_SIZE(formats)) | 830 | if (f->index >= ARRAY_SIZE(formats)) |
835 | return -EINVAL; | 831 | return -EINVAL; |
836 | 832 | ||
837 | fmt = &formats[f->index]; | 833 | fmt = &formats[f->index]; |
838 | 834 | ||
839 | strlcpy(f->description, fmt->name, sizeof(f->description)); | 835 | strlcpy(f->description, fmt->name, sizeof(f->description)); |
840 | f->pixelformat = fmt->fourcc; | 836 | f->pixelformat = fmt->fourcc; |
841 | return 0; | 837 | return 0; |
842 | } | 838 | } |
843 | 839 | ||
844 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | 840 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, |
845 | struct v4l2_format *f) | 841 | struct v4l2_format *f) |
846 | { | 842 | { |
847 | struct vivi_fh *fh = priv; | 843 | struct vivi_fh *fh = priv; |
848 | 844 | ||
849 | f->fmt.pix.width = fh->width; | 845 | f->fmt.pix.width = fh->width; |
850 | f->fmt.pix.height = fh->height; | 846 | f->fmt.pix.height = fh->height; |
851 | f->fmt.pix.field = fh->vb_vidq.field; | 847 | f->fmt.pix.field = fh->vb_vidq.field; |
852 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | 848 | f->fmt.pix.pixelformat = fh->fmt->fourcc; |
853 | f->fmt.pix.bytesperline = | 849 | f->fmt.pix.bytesperline = |
854 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | 850 | (f->fmt.pix.width * fh->fmt->depth) >> 3; |
855 | f->fmt.pix.sizeimage = | 851 | f->fmt.pix.sizeimage = |
856 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 852 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
857 | 853 | ||
858 | return (0); | 854 | return (0); |
859 | } | 855 | } |
860 | 856 | ||
861 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | 857 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, |
862 | struct v4l2_format *f) | 858 | struct v4l2_format *f) |
863 | { | 859 | { |
864 | struct vivi_fh *fh = priv; | 860 | struct vivi_fh *fh = priv; |
865 | struct vivi_dev *dev = fh->dev; | 861 | struct vivi_dev *dev = fh->dev; |
866 | struct vivi_fmt *fmt; | 862 | struct vivi_fmt *fmt; |
867 | enum v4l2_field field; | 863 | enum v4l2_field field; |
868 | unsigned int maxw, maxh; | 864 | unsigned int maxw, maxh; |
869 | 865 | ||
870 | fmt = get_format(f); | 866 | fmt = get_format(f); |
871 | if (!fmt) { | 867 | if (!fmt) { |
872 | dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", | 868 | dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", |
873 | f->fmt.pix.pixelformat); | 869 | f->fmt.pix.pixelformat); |
874 | return -EINVAL; | 870 | return -EINVAL; |
875 | } | 871 | } |
876 | 872 | ||
877 | field = f->fmt.pix.field; | 873 | field = f->fmt.pix.field; |
878 | 874 | ||
879 | if (field == V4L2_FIELD_ANY) { | 875 | if (field == V4L2_FIELD_ANY) { |
880 | field = V4L2_FIELD_INTERLACED; | 876 | field = V4L2_FIELD_INTERLACED; |
881 | } else if (V4L2_FIELD_INTERLACED != field) { | 877 | } else if (V4L2_FIELD_INTERLACED != field) { |
882 | dprintk(dev, 1, "Field type invalid.\n"); | 878 | dprintk(dev, 1, "Field type invalid.\n"); |
883 | return -EINVAL; | 879 | return -EINVAL; |
884 | } | 880 | } |
885 | 881 | ||
886 | maxw = norm_maxw(); | 882 | maxw = norm_maxw(); |
887 | maxh = norm_maxh(); | 883 | maxh = norm_maxh(); |
888 | 884 | ||
889 | f->fmt.pix.field = field; | 885 | f->fmt.pix.field = field; |
890 | if (f->fmt.pix.height < 32) | 886 | if (f->fmt.pix.height < 32) |
891 | f->fmt.pix.height = 32; | 887 | f->fmt.pix.height = 32; |
892 | if (f->fmt.pix.height > maxh) | 888 | if (f->fmt.pix.height > maxh) |
893 | f->fmt.pix.height = maxh; | 889 | f->fmt.pix.height = maxh; |
894 | if (f->fmt.pix.width < 48) | 890 | if (f->fmt.pix.width < 48) |
895 | f->fmt.pix.width = 48; | 891 | f->fmt.pix.width = 48; |
896 | if (f->fmt.pix.width > maxw) | 892 | if (f->fmt.pix.width > maxw) |
897 | f->fmt.pix.width = maxw; | 893 | f->fmt.pix.width = maxw; |
898 | f->fmt.pix.width &= ~0x03; | 894 | f->fmt.pix.width &= ~0x03; |
899 | f->fmt.pix.bytesperline = | 895 | f->fmt.pix.bytesperline = |
900 | (f->fmt.pix.width * fmt->depth) >> 3; | 896 | (f->fmt.pix.width * fmt->depth) >> 3; |
901 | f->fmt.pix.sizeimage = | 897 | f->fmt.pix.sizeimage = |
902 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 898 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
903 | 899 | ||
904 | return 0; | 900 | return 0; |
905 | } | 901 | } |
906 | 902 | ||
907 | /* precalculate color bar values to speed up rendering */ | 903 | /* precalculate color bar values to speed up rendering */ |
908 | static void precalculate_bars(struct vivi_fh *fh) | 904 | static void precalculate_bars(struct vivi_fh *fh) |
909 | { | 905 | { |
910 | struct vivi_dev *dev = fh->dev; | 906 | struct vivi_dev *dev = fh->dev; |
911 | unsigned char r, g, b; | 907 | unsigned char r, g, b; |
912 | int k, is_yuv; | 908 | int k, is_yuv; |
913 | 909 | ||
914 | fh->input = dev->input; | 910 | fh->input = dev->input; |
915 | 911 | ||
916 | for (k = 0; k < 8; k++) { | 912 | for (k = 0; k < 8; k++) { |
917 | r = bars[fh->input].bar[k][0]; | 913 | r = bars[fh->input].bar[k][0]; |
918 | g = bars[fh->input].bar[k][1]; | 914 | g = bars[fh->input].bar[k][1]; |
919 | b = bars[fh->input].bar[k][2]; | 915 | b = bars[fh->input].bar[k][2]; |
920 | is_yuv = 0; | 916 | is_yuv = 0; |
921 | 917 | ||
922 | switch (fh->fmt->fourcc) { | 918 | switch (fh->fmt->fourcc) { |
923 | case V4L2_PIX_FMT_YUYV: | 919 | case V4L2_PIX_FMT_YUYV: |
924 | case V4L2_PIX_FMT_UYVY: | 920 | case V4L2_PIX_FMT_UYVY: |
925 | is_yuv = 1; | 921 | is_yuv = 1; |
926 | break; | 922 | break; |
927 | case V4L2_PIX_FMT_RGB565: | 923 | case V4L2_PIX_FMT_RGB565: |
928 | case V4L2_PIX_FMT_RGB565X: | 924 | case V4L2_PIX_FMT_RGB565X: |
929 | r >>= 3; | 925 | r >>= 3; |
930 | g >>= 2; | 926 | g >>= 2; |
931 | b >>= 3; | 927 | b >>= 3; |
932 | break; | 928 | break; |
933 | case V4L2_PIX_FMT_RGB555: | 929 | case V4L2_PIX_FMT_RGB555: |
934 | case V4L2_PIX_FMT_RGB555X: | 930 | case V4L2_PIX_FMT_RGB555X: |
935 | r >>= 3; | 931 | r >>= 3; |
936 | g >>= 3; | 932 | g >>= 3; |
937 | b >>= 3; | 933 | b >>= 3; |
938 | break; | 934 | break; |
939 | } | 935 | } |
940 | 936 | ||
941 | if (is_yuv) { | 937 | if (is_yuv) { |
942 | fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ | 938 | fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ |
943 | fh->bars[k][1] = TO_U(r, g, b); /* Cb */ | 939 | fh->bars[k][1] = TO_U(r, g, b); /* Cb */ |
944 | fh->bars[k][2] = TO_V(r, g, b); /* Cr */ | 940 | fh->bars[k][2] = TO_V(r, g, b); /* Cr */ |
945 | } else { | 941 | } else { |
946 | fh->bars[k][0] = r; | 942 | fh->bars[k][0] = r; |
947 | fh->bars[k][1] = g; | 943 | fh->bars[k][1] = g; |
948 | fh->bars[k][2] = b; | 944 | fh->bars[k][2] = b; |
949 | } | 945 | } |
950 | } | 946 | } |
951 | 947 | ||
952 | } | 948 | } |
953 | 949 | ||
954 | /*FIXME: This seems to be generic enough to be at videodev2 */ | 950 | /*FIXME: This seems to be generic enough to be at videodev2 */ |
955 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 951 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
956 | struct v4l2_format *f) | 952 | struct v4l2_format *f) |
957 | { | 953 | { |
958 | struct vivi_fh *fh = priv; | 954 | struct vivi_fh *fh = priv; |
959 | struct videobuf_queue *q = &fh->vb_vidq; | 955 | struct videobuf_queue *q = &fh->vb_vidq; |
960 | 956 | ||
961 | int ret = vidioc_try_fmt_vid_cap(file, fh, f); | 957 | int ret = vidioc_try_fmt_vid_cap(file, fh, f); |
962 | if (ret < 0) | 958 | if (ret < 0) |
963 | return ret; | 959 | return ret; |
964 | 960 | ||
965 | mutex_lock(&q->vb_lock); | 961 | mutex_lock(&q->vb_lock); |
966 | 962 | ||
967 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { | 963 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { |
968 | dprintk(fh->dev, 1, "%s queue busy\n", __func__); | 964 | dprintk(fh->dev, 1, "%s queue busy\n", __func__); |
969 | ret = -EBUSY; | 965 | ret = -EBUSY; |
970 | goto out; | 966 | goto out; |
971 | } | 967 | } |
972 | 968 | ||
973 | fh->fmt = get_format(f); | 969 | fh->fmt = get_format(f); |
974 | fh->width = f->fmt.pix.width; | 970 | fh->width = f->fmt.pix.width; |
975 | fh->height = f->fmt.pix.height; | 971 | fh->height = f->fmt.pix.height; |
976 | fh->vb_vidq.field = f->fmt.pix.field; | 972 | fh->vb_vidq.field = f->fmt.pix.field; |
977 | fh->type = f->type; | 973 | fh->type = f->type; |
978 | 974 | ||
979 | precalculate_bars(fh); | 975 | precalculate_bars(fh); |
980 | 976 | ||
981 | ret = 0; | 977 | ret = 0; |
982 | out: | 978 | out: |
983 | mutex_unlock(&q->vb_lock); | 979 | mutex_unlock(&q->vb_lock); |
984 | 980 | ||
985 | return ret; | 981 | return ret; |
986 | } | 982 | } |
987 | 983 | ||
988 | static int vidioc_reqbufs(struct file *file, void *priv, | 984 | static int vidioc_reqbufs(struct file *file, void *priv, |
989 | struct v4l2_requestbuffers *p) | 985 | struct v4l2_requestbuffers *p) |
990 | { | 986 | { |
991 | struct vivi_fh *fh = priv; | 987 | struct vivi_fh *fh = priv; |
992 | 988 | ||
993 | return (videobuf_reqbufs(&fh->vb_vidq, p)); | 989 | return (videobuf_reqbufs(&fh->vb_vidq, p)); |
994 | } | 990 | } |
995 | 991 | ||
996 | static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) | 992 | static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) |
997 | { | 993 | { |
998 | struct vivi_fh *fh = priv; | 994 | struct vivi_fh *fh = priv; |
999 | 995 | ||
1000 | return (videobuf_querybuf(&fh->vb_vidq, p)); | 996 | return (videobuf_querybuf(&fh->vb_vidq, p)); |
1001 | } | 997 | } |
1002 | 998 | ||
1003 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | 999 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) |
1004 | { | 1000 | { |
1005 | struct vivi_fh *fh = priv; | 1001 | struct vivi_fh *fh = priv; |
1006 | 1002 | ||
1007 | return (videobuf_qbuf(&fh->vb_vidq, p)); | 1003 | return (videobuf_qbuf(&fh->vb_vidq, p)); |
1008 | } | 1004 | } |
1009 | 1005 | ||
1010 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | 1006 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) |
1011 | { | 1007 | { |
1012 | struct vivi_fh *fh = priv; | 1008 | struct vivi_fh *fh = priv; |
1013 | 1009 | ||
1014 | return (videobuf_dqbuf(&fh->vb_vidq, p, | 1010 | return (videobuf_dqbuf(&fh->vb_vidq, p, |
1015 | file->f_flags & O_NONBLOCK)); | 1011 | file->f_flags & O_NONBLOCK)); |
1016 | } | 1012 | } |
1017 | 1013 | ||
1018 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1014 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1019 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) | 1015 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) |
1020 | { | 1016 | { |
1021 | struct vivi_fh *fh = priv; | 1017 | struct vivi_fh *fh = priv; |
1022 | 1018 | ||
1023 | return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); | 1019 | return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); |
1024 | } | 1020 | } |
1025 | #endif | 1021 | #endif |
1026 | 1022 | ||
1027 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | 1023 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
1028 | { | 1024 | { |
1029 | struct vivi_fh *fh = priv; | 1025 | struct vivi_fh *fh = priv; |
1030 | 1026 | ||
1031 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1027 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1032 | return -EINVAL; | 1028 | return -EINVAL; |
1033 | if (i != fh->type) | 1029 | if (i != fh->type) |
1034 | return -EINVAL; | 1030 | return -EINVAL; |
1035 | 1031 | ||
1036 | return videobuf_streamon(&fh->vb_vidq); | 1032 | return videobuf_streamon(&fh->vb_vidq); |
1037 | } | 1033 | } |
1038 | 1034 | ||
1039 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | 1035 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
1040 | { | 1036 | { |
1041 | struct vivi_fh *fh = priv; | 1037 | struct vivi_fh *fh = priv; |
1042 | 1038 | ||
1043 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1039 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1044 | return -EINVAL; | 1040 | return -EINVAL; |
1045 | if (i != fh->type) | 1041 | if (i != fh->type) |
1046 | return -EINVAL; | 1042 | return -EINVAL; |
1047 | 1043 | ||
1048 | return videobuf_streamoff(&fh->vb_vidq); | 1044 | return videobuf_streamoff(&fh->vb_vidq); |
1049 | } | 1045 | } |
1050 | 1046 | ||
1051 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | 1047 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) |
1052 | { | 1048 | { |
1053 | return 0; | 1049 | return 0; |
1054 | } | 1050 | } |
1055 | 1051 | ||
1056 | /* only one input in this sample driver */ | 1052 | /* only one input in this sample driver */ |
1057 | static int vidioc_enum_input(struct file *file, void *priv, | 1053 | static int vidioc_enum_input(struct file *file, void *priv, |
1058 | struct v4l2_input *inp) | 1054 | struct v4l2_input *inp) |
1059 | { | 1055 | { |
1060 | if (inp->index >= NUM_INPUTS) | 1056 | if (inp->index >= NUM_INPUTS) |
1061 | return -EINVAL; | 1057 | return -EINVAL; |
1062 | 1058 | ||
1063 | inp->type = V4L2_INPUT_TYPE_CAMERA; | 1059 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
1064 | inp->std = V4L2_STD_525_60; | 1060 | inp->std = V4L2_STD_525_60; |
1065 | sprintf(inp->name, "Camera %u", inp->index); | 1061 | sprintf(inp->name, "Camera %u", inp->index); |
1066 | 1062 | ||
1067 | return (0); | 1063 | return (0); |
1068 | } | 1064 | } |
1069 | 1065 | ||
1070 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | 1066 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) |
1071 | { | 1067 | { |
1072 | struct vivi_fh *fh = priv; | 1068 | struct vivi_fh *fh = priv; |
1073 | struct vivi_dev *dev = fh->dev; | 1069 | struct vivi_dev *dev = fh->dev; |
1074 | 1070 | ||
1075 | *i = dev->input; | 1071 | *i = dev->input; |
1076 | 1072 | ||
1077 | return (0); | 1073 | return (0); |
1078 | } | 1074 | } |
1079 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | 1075 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) |
1080 | { | 1076 | { |
1081 | struct vivi_fh *fh = priv; | 1077 | struct vivi_fh *fh = priv; |
1082 | struct vivi_dev *dev = fh->dev; | 1078 | struct vivi_dev *dev = fh->dev; |
1083 | 1079 | ||
1084 | if (i >= NUM_INPUTS) | 1080 | if (i >= NUM_INPUTS) |
1085 | return -EINVAL; | 1081 | return -EINVAL; |
1086 | 1082 | ||
1087 | dev->input = i; | 1083 | dev->input = i; |
1088 | precalculate_bars(fh); | 1084 | precalculate_bars(fh); |
1089 | 1085 | ||
1090 | return (0); | 1086 | return (0); |
1091 | } | 1087 | } |
1092 | 1088 | ||
1093 | /* --- controls ---------------------------------------------- */ | 1089 | /* --- controls ---------------------------------------------- */ |
1094 | static int vidioc_queryctrl(struct file *file, void *priv, | 1090 | static int vidioc_queryctrl(struct file *file, void *priv, |
1095 | struct v4l2_queryctrl *qc) | 1091 | struct v4l2_queryctrl *qc) |
1096 | { | 1092 | { |
1097 | int i; | 1093 | int i; |
1098 | 1094 | ||
1099 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | 1095 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) |
1100 | if (qc->id && qc->id == vivi_qctrl[i].id) { | 1096 | if (qc->id && qc->id == vivi_qctrl[i].id) { |
1101 | memcpy(qc, &(vivi_qctrl[i]), | 1097 | memcpy(qc, &(vivi_qctrl[i]), |
1102 | sizeof(*qc)); | 1098 | sizeof(*qc)); |
1103 | return (0); | 1099 | return (0); |
1104 | } | 1100 | } |
1105 | 1101 | ||
1106 | return -EINVAL; | 1102 | return -EINVAL; |
1107 | } | 1103 | } |
1108 | 1104 | ||
1109 | static int vidioc_g_ctrl(struct file *file, void *priv, | 1105 | static int vidioc_g_ctrl(struct file *file, void *priv, |
1110 | struct v4l2_control *ctrl) | 1106 | struct v4l2_control *ctrl) |
1111 | { | 1107 | { |
1112 | struct vivi_fh *fh = priv; | 1108 | struct vivi_fh *fh = priv; |
1113 | struct vivi_dev *dev = fh->dev; | 1109 | struct vivi_dev *dev = fh->dev; |
1114 | int i; | 1110 | int i; |
1115 | 1111 | ||
1116 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | 1112 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) |
1117 | if (ctrl->id == vivi_qctrl[i].id) { | 1113 | if (ctrl->id == vivi_qctrl[i].id) { |
1118 | ctrl->value = dev->qctl_regs[i]; | 1114 | ctrl->value = dev->qctl_regs[i]; |
1119 | return 0; | 1115 | return 0; |
1120 | } | 1116 | } |
1121 | 1117 | ||
1122 | return -EINVAL; | 1118 | return -EINVAL; |
1123 | } | 1119 | } |
1124 | static int vidioc_s_ctrl(struct file *file, void *priv, | 1120 | static int vidioc_s_ctrl(struct file *file, void *priv, |
1125 | struct v4l2_control *ctrl) | 1121 | struct v4l2_control *ctrl) |
1126 | { | 1122 | { |
1127 | struct vivi_fh *fh = priv; | 1123 | struct vivi_fh *fh = priv; |
1128 | struct vivi_dev *dev = fh->dev; | 1124 | struct vivi_dev *dev = fh->dev; |
1129 | int i; | 1125 | int i; |
1130 | 1126 | ||
1131 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | 1127 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) |
1132 | if (ctrl->id == vivi_qctrl[i].id) { | 1128 | if (ctrl->id == vivi_qctrl[i].id) { |
1133 | if (ctrl->value < vivi_qctrl[i].minimum || | 1129 | if (ctrl->value < vivi_qctrl[i].minimum || |
1134 | ctrl->value > vivi_qctrl[i].maximum) { | 1130 | ctrl->value > vivi_qctrl[i].maximum) { |
1135 | return -ERANGE; | 1131 | return -ERANGE; |
1136 | } | 1132 | } |
1137 | dev->qctl_regs[i] = ctrl->value; | 1133 | dev->qctl_regs[i] = ctrl->value; |
1138 | return 0; | 1134 | return 0; |
1139 | } | 1135 | } |
1140 | return -EINVAL; | 1136 | return -EINVAL; |
1141 | } | 1137 | } |
1142 | 1138 | ||
1143 | /* ------------------------------------------------------------------ | 1139 | /* ------------------------------------------------------------------ |
1144 | File operations for the device | 1140 | File operations for the device |
1145 | ------------------------------------------------------------------*/ | 1141 | ------------------------------------------------------------------*/ |
1146 | 1142 | ||
1147 | static int vivi_open(struct file *file) | 1143 | static int vivi_open(struct file *file) |
1148 | { | 1144 | { |
1149 | struct vivi_dev *dev = video_drvdata(file); | 1145 | struct vivi_dev *dev = video_drvdata(file); |
1150 | struct vivi_fh *fh = NULL; | 1146 | struct vivi_fh *fh = NULL; |
1151 | int retval = 0; | 1147 | int retval = 0; |
1152 | 1148 | ||
1153 | mutex_lock(&dev->mutex); | 1149 | mutex_lock(&dev->mutex); |
1154 | dev->users++; | 1150 | dev->users++; |
1155 | 1151 | ||
1156 | if (dev->users > 1) { | 1152 | if (dev->users > 1) { |
1157 | dev->users--; | 1153 | dev->users--; |
1158 | mutex_unlock(&dev->mutex); | 1154 | mutex_unlock(&dev->mutex); |
1159 | return -EBUSY; | 1155 | return -EBUSY; |
1160 | } | 1156 | } |
1161 | 1157 | ||
1162 | dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num, | 1158 | dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num, |
1163 | v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); | 1159 | v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); |
1164 | 1160 | ||
1165 | /* allocate + initialize per filehandle data */ | 1161 | /* allocate + initialize per filehandle data */ |
1166 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 1162 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
1167 | if (NULL == fh) { | 1163 | if (NULL == fh) { |
1168 | dev->users--; | 1164 | dev->users--; |
1169 | retval = -ENOMEM; | 1165 | retval = -ENOMEM; |
1170 | } | 1166 | } |
1171 | mutex_unlock(&dev->mutex); | 1167 | mutex_unlock(&dev->mutex); |
1172 | 1168 | ||
1173 | if (retval) | 1169 | if (retval) |
1174 | return retval; | 1170 | return retval; |
1175 | 1171 | ||
1176 | file->private_data = fh; | 1172 | file->private_data = fh; |
1177 | fh->dev = dev; | 1173 | fh->dev = dev; |
1178 | 1174 | ||
1179 | fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1175 | fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1180 | fh->fmt = &formats[0]; | 1176 | fh->fmt = &formats[0]; |
1181 | fh->width = 640; | 1177 | fh->width = 640; |
1182 | fh->height = 480; | 1178 | fh->height = 480; |
1183 | 1179 | ||
1184 | /* Resets frame counters */ | 1180 | /* Resets frame counters */ |
1185 | dev->h = 0; | 1181 | dev->h = 0; |
1186 | dev->m = 0; | 1182 | dev->m = 0; |
1187 | dev->s = 0; | 1183 | dev->s = 0; |
1188 | dev->ms = 0; | 1184 | dev->ms = 0; |
1189 | dev->mv_count = 0; | 1185 | dev->mv_count = 0; |
1190 | dev->jiffies = jiffies; | 1186 | dev->jiffies = jiffies; |
1191 | sprintf(dev->timestr, "%02d:%02d:%02d:%03d", | 1187 | sprintf(dev->timestr, "%02d:%02d:%02d:%03d", |
1192 | dev->h, dev->m, dev->s, dev->ms); | 1188 | dev->h, dev->m, dev->s, dev->ms); |
1193 | 1189 | ||
1194 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, | 1190 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, |
1195 | NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, | 1191 | NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, |
1196 | sizeof(struct vivi_buffer), fh); | 1192 | sizeof(struct vivi_buffer), fh); |
1197 | 1193 | ||
1198 | vivi_start_thread(fh); | 1194 | vivi_start_thread(fh); |
1199 | 1195 | ||
1200 | return 0; | 1196 | return 0; |
1201 | } | 1197 | } |
1202 | 1198 | ||
1203 | static ssize_t | 1199 | static ssize_t |
1204 | vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 1200 | vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
1205 | { | 1201 | { |
1206 | struct vivi_fh *fh = file->private_data; | 1202 | struct vivi_fh *fh = file->private_data; |
1207 | 1203 | ||
1208 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 1204 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1209 | return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, | 1205 | return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, |
1210 | file->f_flags & O_NONBLOCK); | 1206 | file->f_flags & O_NONBLOCK); |
1211 | } | 1207 | } |
1212 | return 0; | 1208 | return 0; |
1213 | } | 1209 | } |
1214 | 1210 | ||
1215 | static unsigned int | 1211 | static unsigned int |
1216 | vivi_poll(struct file *file, struct poll_table_struct *wait) | 1212 | vivi_poll(struct file *file, struct poll_table_struct *wait) |
1217 | { | 1213 | { |
1218 | struct vivi_fh *fh = file->private_data; | 1214 | struct vivi_fh *fh = file->private_data; |
1219 | struct vivi_dev *dev = fh->dev; | 1215 | struct vivi_dev *dev = fh->dev; |
1220 | struct videobuf_queue *q = &fh->vb_vidq; | 1216 | struct videobuf_queue *q = &fh->vb_vidq; |
1221 | 1217 | ||
1222 | dprintk(dev, 1, "%s\n", __func__); | 1218 | dprintk(dev, 1, "%s\n", __func__); |
1223 | 1219 | ||
1224 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) | 1220 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) |
1225 | return POLLERR; | 1221 | return POLLERR; |
1226 | 1222 | ||
1227 | return videobuf_poll_stream(file, q, wait); | 1223 | return videobuf_poll_stream(file, q, wait); |
1228 | } | 1224 | } |
1229 | 1225 | ||
1230 | static int vivi_close(struct file *file) | 1226 | static int vivi_close(struct file *file) |
1231 | { | 1227 | { |
1232 | struct vivi_fh *fh = file->private_data; | 1228 | struct vivi_fh *fh = file->private_data; |
1233 | struct vivi_dev *dev = fh->dev; | 1229 | struct vivi_dev *dev = fh->dev; |
1234 | struct vivi_dmaqueue *vidq = &dev->vidq; | 1230 | struct vivi_dmaqueue *vidq = &dev->vidq; |
1235 | 1231 | ||
1236 | int minor = video_devdata(file)->minor; | 1232 | int minor = video_devdata(file)->minor; |
1237 | 1233 | ||
1238 | vivi_stop_thread(vidq); | 1234 | vivi_stop_thread(vidq); |
1239 | videobuf_stop(&fh->vb_vidq); | 1235 | videobuf_stop(&fh->vb_vidq); |
1240 | videobuf_mmap_free(&fh->vb_vidq); | 1236 | videobuf_mmap_free(&fh->vb_vidq); |
1241 | 1237 | ||
1242 | kfree(fh); | 1238 | kfree(fh); |
1243 | 1239 | ||
1244 | mutex_lock(&dev->mutex); | 1240 | mutex_lock(&dev->mutex); |
1245 | dev->users--; | 1241 | dev->users--; |
1246 | mutex_unlock(&dev->mutex); | 1242 | mutex_unlock(&dev->mutex); |
1247 | 1243 | ||
1248 | dprintk(dev, 1, "close called (minor=%d, users=%d)\n", | 1244 | dprintk(dev, 1, "close called (minor=%d, users=%d)\n", |
1249 | minor, dev->users); | 1245 | minor, dev->users); |
1250 | 1246 | ||
1251 | return 0; | 1247 | return 0; |
1252 | } | 1248 | } |
1253 | 1249 | ||
1254 | static int vivi_mmap(struct file *file, struct vm_area_struct *vma) | 1250 | static int vivi_mmap(struct file *file, struct vm_area_struct *vma) |
1255 | { | 1251 | { |
1256 | struct vivi_fh *fh = file->private_data; | 1252 | struct vivi_fh *fh = file->private_data; |
1257 | struct vivi_dev *dev = fh->dev; | 1253 | struct vivi_dev *dev = fh->dev; |
1258 | int ret; | 1254 | int ret; |
1259 | 1255 | ||
1260 | dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | 1256 | dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); |
1261 | 1257 | ||
1262 | ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); | 1258 | ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); |
1263 | 1259 | ||
1264 | dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", | 1260 | dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", |
1265 | (unsigned long)vma->vm_start, | 1261 | (unsigned long)vma->vm_start, |
1266 | (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, | 1262 | (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, |
1267 | ret); | 1263 | ret); |
1268 | 1264 | ||
1269 | return ret; | 1265 | return ret; |
1270 | } | 1266 | } |
1271 | 1267 | ||
1272 | static const struct v4l2_file_operations vivi_fops = { | 1268 | static const struct v4l2_file_operations vivi_fops = { |
1273 | .owner = THIS_MODULE, | 1269 | .owner = THIS_MODULE, |
1274 | .open = vivi_open, | 1270 | .open = vivi_open, |
1275 | .release = vivi_close, | 1271 | .release = vivi_close, |
1276 | .read = vivi_read, | 1272 | .read = vivi_read, |
1277 | .poll = vivi_poll, | 1273 | .poll = vivi_poll, |
1278 | .ioctl = video_ioctl2, /* V4L2 ioctl handler */ | 1274 | .ioctl = video_ioctl2, /* V4L2 ioctl handler */ |
1279 | .mmap = vivi_mmap, | 1275 | .mmap = vivi_mmap, |
1280 | }; | 1276 | }; |
1281 | 1277 | ||
1282 | static const struct v4l2_ioctl_ops vivi_ioctl_ops = { | 1278 | static const struct v4l2_ioctl_ops vivi_ioctl_ops = { |
1283 | .vidioc_querycap = vidioc_querycap, | 1279 | .vidioc_querycap = vidioc_querycap, |
1284 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | 1280 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1285 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 1281 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
1286 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | 1282 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, |
1287 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | 1283 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, |
1288 | .vidioc_reqbufs = vidioc_reqbufs, | 1284 | .vidioc_reqbufs = vidioc_reqbufs, |
1289 | .vidioc_querybuf = vidioc_querybuf, | 1285 | .vidioc_querybuf = vidioc_querybuf, |
1290 | .vidioc_qbuf = vidioc_qbuf, | 1286 | .vidioc_qbuf = vidioc_qbuf, |
1291 | .vidioc_dqbuf = vidioc_dqbuf, | 1287 | .vidioc_dqbuf = vidioc_dqbuf, |
1292 | .vidioc_s_std = vidioc_s_std, | 1288 | .vidioc_s_std = vidioc_s_std, |
1293 | .vidioc_enum_input = vidioc_enum_input, | 1289 | .vidioc_enum_input = vidioc_enum_input, |
1294 | .vidioc_g_input = vidioc_g_input, | 1290 | .vidioc_g_input = vidioc_g_input, |
1295 | .vidioc_s_input = vidioc_s_input, | 1291 | .vidioc_s_input = vidioc_s_input, |
1296 | .vidioc_queryctrl = vidioc_queryctrl, | 1292 | .vidioc_queryctrl = vidioc_queryctrl, |
1297 | .vidioc_g_ctrl = vidioc_g_ctrl, | 1293 | .vidioc_g_ctrl = vidioc_g_ctrl, |
1298 | .vidioc_s_ctrl = vidioc_s_ctrl, | 1294 | .vidioc_s_ctrl = vidioc_s_ctrl, |
1299 | .vidioc_streamon = vidioc_streamon, | 1295 | .vidioc_streamon = vidioc_streamon, |
1300 | .vidioc_streamoff = vidioc_streamoff, | 1296 | .vidioc_streamoff = vidioc_streamoff, |
1301 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1297 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1302 | .vidiocgmbuf = vidiocgmbuf, | 1298 | .vidiocgmbuf = vidiocgmbuf, |
1303 | #endif | 1299 | #endif |
1304 | }; | 1300 | }; |
1305 | 1301 | ||
1306 | static struct video_device vivi_template = { | 1302 | static struct video_device vivi_template = { |
1307 | .name = "vivi", | 1303 | .name = "vivi", |
1308 | .fops = &vivi_fops, | 1304 | .fops = &vivi_fops, |
1309 | .ioctl_ops = &vivi_ioctl_ops, | 1305 | .ioctl_ops = &vivi_ioctl_ops, |
1310 | .minor = -1, | 1306 | .minor = -1, |
1311 | .release = video_device_release, | 1307 | .release = video_device_release, |
1312 | 1308 | ||
1313 | .tvnorms = V4L2_STD_525_60, | 1309 | .tvnorms = V4L2_STD_525_60, |
1314 | .current_norm = V4L2_STD_NTSC_M, | 1310 | .current_norm = V4L2_STD_NTSC_M, |
1315 | }; | 1311 | }; |
1316 | 1312 | ||
1317 | /* ----------------------------------------------------------------- | 1313 | /* ----------------------------------------------------------------- |
1318 | Initialization and module stuff | 1314 | Initialization and module stuff |
1319 | ------------------------------------------------------------------*/ | 1315 | ------------------------------------------------------------------*/ |
1320 | 1316 | ||
1321 | static int vivi_release(void) | 1317 | static int vivi_release(void) |
1322 | { | 1318 | { |
1323 | struct vivi_dev *dev; | 1319 | struct vivi_dev *dev; |
1324 | struct list_head *list; | 1320 | struct list_head *list; |
1325 | 1321 | ||
1326 | while (!list_empty(&vivi_devlist)) { | 1322 | while (!list_empty(&vivi_devlist)) { |
1327 | list = vivi_devlist.next; | 1323 | list = vivi_devlist.next; |
1328 | list_del(list); | 1324 | list_del(list); |
1329 | dev = list_entry(list, struct vivi_dev, vivi_devlist); | 1325 | dev = list_entry(list, struct vivi_dev, vivi_devlist); |
1330 | 1326 | ||
1331 | v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n", | 1327 | v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n", |
1332 | dev->vfd->num); | 1328 | dev->vfd->num); |
1333 | video_unregister_device(dev->vfd); | 1329 | video_unregister_device(dev->vfd); |
1334 | v4l2_device_unregister(&dev->v4l2_dev); | 1330 | v4l2_device_unregister(&dev->v4l2_dev); |
1335 | kfree(dev); | 1331 | kfree(dev); |
1336 | } | 1332 | } |
1337 | 1333 | ||
1338 | return 0; | 1334 | return 0; |
1339 | } | 1335 | } |
1340 | 1336 | ||
1341 | static int __init vivi_create_instance(int inst) | 1337 | static int __init vivi_create_instance(int inst) |
1342 | { | 1338 | { |
1343 | struct vivi_dev *dev; | 1339 | struct vivi_dev *dev; |
1344 | struct video_device *vfd; | 1340 | struct video_device *vfd; |
1345 | int ret, i; | 1341 | int ret, i; |
1346 | 1342 | ||
1347 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 1343 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1348 | if (!dev) | 1344 | if (!dev) |
1349 | return -ENOMEM; | 1345 | return -ENOMEM; |
1350 | 1346 | ||
1351 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), | 1347 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), |
1352 | "%s-%03d", VIVI_MODULE_NAME, inst); | 1348 | "%s-%03d", VIVI_MODULE_NAME, inst); |
1353 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); | 1349 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); |
1354 | if (ret) | 1350 | if (ret) |
1355 | goto free_dev; | 1351 | goto free_dev; |
1356 | 1352 | ||
1357 | /* init video dma queues */ | 1353 | /* init video dma queues */ |
1358 | INIT_LIST_HEAD(&dev->vidq.active); | 1354 | INIT_LIST_HEAD(&dev->vidq.active); |
1359 | init_waitqueue_head(&dev->vidq.wq); | 1355 | init_waitqueue_head(&dev->vidq.wq); |
1360 | 1356 | ||
1361 | /* initialize locks */ | 1357 | /* initialize locks */ |
1362 | spin_lock_init(&dev->slock); | 1358 | spin_lock_init(&dev->slock); |
1363 | mutex_init(&dev->mutex); | 1359 | mutex_init(&dev->mutex); |
1364 | 1360 | ||
1365 | ret = -ENOMEM; | 1361 | ret = -ENOMEM; |
1366 | vfd = video_device_alloc(); | 1362 | vfd = video_device_alloc(); |
1367 | if (!vfd) | 1363 | if (!vfd) |
1368 | goto unreg_dev; | 1364 | goto unreg_dev; |
1369 | 1365 | ||
1370 | *vfd = vivi_template; | 1366 | *vfd = vivi_template; |
1371 | 1367 | ||
1372 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); | 1368 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); |
1373 | if (ret < 0) | 1369 | if (ret < 0) |
1374 | goto rel_vdev; | 1370 | goto rel_vdev; |
1375 | 1371 | ||
1376 | video_set_drvdata(vfd, dev); | 1372 | video_set_drvdata(vfd, dev); |
1377 | 1373 | ||
1378 | /* Set all controls to their default value. */ | 1374 | /* Set all controls to their default value. */ |
1379 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) | 1375 | for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) |
1380 | dev->qctl_regs[i] = vivi_qctrl[i].default_value; | 1376 | dev->qctl_regs[i] = vivi_qctrl[i].default_value; |
1381 | 1377 | ||
1382 | /* Now that everything is fine, let's add it to device list */ | 1378 | /* Now that everything is fine, let's add it to device list */ |
1383 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); | 1379 | list_add_tail(&dev->vivi_devlist, &vivi_devlist); |
1384 | 1380 | ||
1385 | snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", | 1381 | snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", |
1386 | vivi_template.name, vfd->num); | 1382 | vivi_template.name, vfd->num); |
1387 | 1383 | ||
1388 | if (video_nr >= 0) | 1384 | if (video_nr >= 0) |
1389 | video_nr++; | 1385 | video_nr++; |
1390 | 1386 | ||
1391 | dev->vfd = vfd; | 1387 | dev->vfd = vfd; |
1392 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n", | 1388 | v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n", |
1393 | vfd->num); | 1389 | vfd->num); |
1394 | return 0; | 1390 | return 0; |
1395 | 1391 | ||
1396 | rel_vdev: | 1392 | rel_vdev: |
1397 | video_device_release(vfd); | 1393 | video_device_release(vfd); |
1398 | unreg_dev: | 1394 | unreg_dev: |
1399 | v4l2_device_unregister(&dev->v4l2_dev); | 1395 | v4l2_device_unregister(&dev->v4l2_dev); |
1400 | free_dev: | 1396 | free_dev: |
1401 | kfree(dev); | 1397 | kfree(dev); |
1402 | return ret; | 1398 | return ret; |
1403 | } | 1399 | } |
1404 | 1400 | ||
1405 | /* This routine allocates from 1 to n_devs virtual drivers. | 1401 | /* This routine allocates from 1 to n_devs virtual drivers. |
1406 | 1402 | ||
1407 | The real maximum number of virtual drivers will depend on how many drivers | 1403 | The real maximum number of virtual drivers will depend on how many drivers |
1408 | will succeed. This is limited to the maximum number of devices that | 1404 | will succeed. This is limited to the maximum number of devices that |
1409 | videodev supports, which is equal to VIDEO_NUM_DEVICES. | 1405 | videodev supports, which is equal to VIDEO_NUM_DEVICES. |
1410 | */ | 1406 | */ |
1411 | static int __init vivi_init(void) | 1407 | static int __init vivi_init(void) |
1412 | { | 1408 | { |
1413 | int ret, i; | 1409 | int ret, i; |
1414 | 1410 | ||
1415 | if (n_devs <= 0) | 1411 | if (n_devs <= 0) |
1416 | n_devs = 1; | 1412 | n_devs = 1; |
1417 | 1413 | ||
1418 | for (i = 0; i < n_devs; i++) { | 1414 | for (i = 0; i < n_devs; i++) { |
1419 | ret = vivi_create_instance(i); | 1415 | ret = vivi_create_instance(i); |
1420 | if (ret) { | 1416 | if (ret) { |
1421 | /* If some instantiations succeeded, keep driver */ | 1417 | /* If some instantiations succeeded, keep driver */ |
1422 | if (i) | 1418 | if (i) |
1423 | ret = 0; | 1419 | ret = 0; |
1424 | break; | 1420 | break; |
1425 | } | 1421 | } |
1426 | } | 1422 | } |
1427 | 1423 | ||
1428 | if (ret < 0) { | 1424 | if (ret < 0) { |
1429 | printk(KERN_INFO "Error %d while loading vivi driver\n", ret); | 1425 | printk(KERN_INFO "Error %d while loading vivi driver\n", ret); |
1430 | return ret; | 1426 | return ret; |
1431 | } | 1427 | } |
1432 | 1428 | ||
1433 | printk(KERN_INFO "Video Technology Magazine Virtual Video " | 1429 | printk(KERN_INFO "Video Technology Magazine Virtual Video " |
1434 | "Capture Board ver %u.%u.%u successfully loaded.\n", | 1430 | "Capture Board ver %u.%u.%u successfully loaded.\n", |
1435 | (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, | 1431 | (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, |
1436 | VIVI_VERSION & 0xFF); | 1432 | VIVI_VERSION & 0xFF); |
1437 | 1433 | ||
1438 | /* n_devs will reflect the actual number of allocated devices */ | 1434 | /* n_devs will reflect the actual number of allocated devices */ |
1439 | n_devs = i; | 1435 | n_devs = i; |
1440 | 1436 | ||
1441 | return ret; | 1437 | return ret; |
1442 | } | 1438 | } |
1443 | 1439 | ||
1444 | static void __exit vivi_exit(void) | 1440 | static void __exit vivi_exit(void) |
1445 | { | 1441 | { |
1446 | vivi_release(); | 1442 | vivi_release(); |
1447 | } | 1443 | } |
1448 | 1444 | ||
1449 | module_init(vivi_init); | 1445 | module_init(vivi_init); |
1450 | module_exit(vivi_exit); | 1446 | module_exit(vivi_exit); |
1451 | 1447 |
drivers/media/video/w9966.c
1 | /* | 1 | /* |
2 | Winbond w9966cf Webcam parport driver. | 2 | Winbond w9966cf Webcam parport driver. |
3 | 3 | ||
4 | Version 0.32 | 4 | Version 0.32 |
5 | 5 | ||
6 | Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> | 6 | Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> |
7 | 7 | ||
8 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. | 11 | (at your option) any later version. |
12 | 12 | ||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. |
17 | 17 | ||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software | 19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | */ | 21 | */ |
22 | /* | 22 | /* |
23 | Supported devices: | 23 | Supported devices: |
24 | *Lifeview FlyCam Supra (using the Philips saa7111a chip) | 24 | *Lifeview FlyCam Supra (using the Philips saa7111a chip) |
25 | 25 | ||
26 | Does any other model using the w9966 interface chip exist ? | 26 | Does any other model using the w9966 interface chip exist ? |
27 | 27 | ||
28 | Todo: | 28 | Todo: |
29 | 29 | ||
30 | *Add a working EPP mode, since DMA ECP read isn't implemented | 30 | *Add a working EPP mode, since DMA ECP read isn't implemented |
31 | in the parport drivers. (That's why it's so sloow) | 31 | in the parport drivers. (That's why it's so sloow) |
32 | 32 | ||
33 | *Add support for other ccd-control chips than the saa7111 | 33 | *Add support for other ccd-control chips than the saa7111 |
34 | please send me feedback on what kind of chips you have. | 34 | please send me feedback on what kind of chips you have. |
35 | 35 | ||
36 | *Add proper probing. I don't know what's wrong with the IEEE1284 | 36 | *Add proper probing. I don't know what's wrong with the IEEE1284 |
37 | parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) | 37 | parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) |
38 | and nibble read seems to be broken for some peripherals. | 38 | and nibble read seems to be broken for some peripherals. |
39 | 39 | ||
40 | *Add probing for onboard SRAM, port directions etc. (if possible) | 40 | *Add probing for onboard SRAM, port directions etc. (if possible) |
41 | 41 | ||
42 | *Add support for the hardware compressed modes (maybe using v4l2) | 42 | *Add support for the hardware compressed modes (maybe using v4l2) |
43 | 43 | ||
44 | *Fix better support for the capture window (no skewed images, v4l | 44 | *Fix better support for the capture window (no skewed images, v4l |
45 | interface to capt. window) | 45 | interface to capt. window) |
46 | 46 | ||
47 | *Probably some bugs that I don't know of | 47 | *Probably some bugs that I don't know of |
48 | 48 | ||
49 | Please support me by sending feedback! | 49 | Please support me by sending feedback! |
50 | 50 | ||
51 | Changes: | 51 | Changes: |
52 | 52 | ||
53 | Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE | 53 | Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE |
54 | and owner support for newer module locks | 54 | and owner support for newer module locks |
55 | */ | 55 | */ |
56 | 56 | ||
57 | #include <linux/module.h> | 57 | #include <linux/module.h> |
58 | #include <linux/init.h> | 58 | #include <linux/init.h> |
59 | #include <linux/delay.h> | 59 | #include <linux/delay.h> |
60 | #include <linux/videodev2.h> | 60 | #include <linux/videodev.h> |
61 | #include <media/v4l2-common.h> | 61 | #include <media/v4l2-common.h> |
62 | #include <media/v4l2-ioctl.h> | 62 | #include <media/v4l2-ioctl.h> |
63 | #include <linux/parport.h> | 63 | #include <linux/parport.h> |
64 | 64 | ||
65 | /*#define DEBUG*/ /* Undef me for production */ | 65 | /*#define DEBUG*/ /* Undef me for production */ |
66 | 66 | ||
67 | #ifdef DEBUG | 67 | #ifdef DEBUG |
68 | #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) | 68 | #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) |
69 | #else | 69 | #else |
70 | #define DPRINTF(x...) | 70 | #define DPRINTF(x...) |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | /* | 73 | /* |
74 | * Defines, simple typedefs etc. | 74 | * Defines, simple typedefs etc. |
75 | */ | 75 | */ |
76 | 76 | ||
77 | #define W9966_DRIVERNAME "W9966CF Webcam" | 77 | #define W9966_DRIVERNAME "W9966CF Webcam" |
78 | #define W9966_MAXCAMS 4 // Maximum number of cameras | 78 | #define W9966_MAXCAMS 4 // Maximum number of cameras |
79 | #define W9966_RBUFFER 2048 // Read buffer (must be an even number) | 79 | #define W9966_RBUFFER 2048 // Read buffer (must be an even number) |
80 | #define W9966_SRAMSIZE 131072 // 128kb | 80 | #define W9966_SRAMSIZE 131072 // 128kb |
81 | #define W9966_SRAMID 0x02 // check w9966cf.pdf | 81 | #define W9966_SRAMID 0x02 // check w9966cf.pdf |
82 | 82 | ||
83 | // Empirically determined window limits | 83 | // Empirically determined window limits |
84 | #define W9966_WND_MIN_X 16 | 84 | #define W9966_WND_MIN_X 16 |
85 | #define W9966_WND_MIN_Y 14 | 85 | #define W9966_WND_MIN_Y 14 |
86 | #define W9966_WND_MAX_X 705 | 86 | #define W9966_WND_MAX_X 705 |
87 | #define W9966_WND_MAX_Y 253 | 87 | #define W9966_WND_MAX_Y 253 |
88 | #define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) | 88 | #define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) |
89 | #define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) | 89 | #define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) |
90 | 90 | ||
91 | // Keep track of our current state | 91 | // Keep track of our current state |
92 | #define W9966_STATE_PDEV 0x01 | 92 | #define W9966_STATE_PDEV 0x01 |
93 | #define W9966_STATE_CLAIMED 0x02 | 93 | #define W9966_STATE_CLAIMED 0x02 |
94 | #define W9966_STATE_VDEV 0x04 | 94 | #define W9966_STATE_VDEV 0x04 |
95 | 95 | ||
96 | #define W9966_I2C_W_ID 0x48 | 96 | #define W9966_I2C_W_ID 0x48 |
97 | #define W9966_I2C_R_ID 0x49 | 97 | #define W9966_I2C_R_ID 0x49 |
98 | #define W9966_I2C_R_DATA 0x08 | 98 | #define W9966_I2C_R_DATA 0x08 |
99 | #define W9966_I2C_R_CLOCK 0x04 | 99 | #define W9966_I2C_R_CLOCK 0x04 |
100 | #define W9966_I2C_W_DATA 0x02 | 100 | #define W9966_I2C_W_DATA 0x02 |
101 | #define W9966_I2C_W_CLOCK 0x01 | 101 | #define W9966_I2C_W_CLOCK 0x01 |
102 | 102 | ||
103 | struct w9966_dev { | 103 | struct w9966_dev { |
104 | unsigned char dev_state; | 104 | unsigned char dev_state; |
105 | unsigned char i2c_state; | 105 | unsigned char i2c_state; |
106 | unsigned short ppmode; | 106 | unsigned short ppmode; |
107 | struct parport* pport; | 107 | struct parport* pport; |
108 | struct pardevice* pdev; | 108 | struct pardevice* pdev; |
109 | struct video_device vdev; | 109 | struct video_device vdev; |
110 | unsigned short width; | 110 | unsigned short width; |
111 | unsigned short height; | 111 | unsigned short height; |
112 | unsigned char brightness; | 112 | unsigned char brightness; |
113 | signed char contrast; | 113 | signed char contrast; |
114 | signed char color; | 114 | signed char color; |
115 | signed char hue; | 115 | signed char hue; |
116 | unsigned long in_use; | 116 | unsigned long in_use; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /* | 119 | /* |
120 | * Module specific properties | 120 | * Module specific properties |
121 | */ | 121 | */ |
122 | 122 | ||
123 | MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); | 123 | MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); |
124 | MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); | 124 | MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); |
125 | MODULE_LICENSE("GPL"); | 125 | MODULE_LICENSE("GPL"); |
126 | 126 | ||
127 | 127 | ||
128 | #ifdef MODULE | 128 | #ifdef MODULE |
129 | static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""}; | 129 | static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""}; |
130 | #else | 130 | #else |
131 | static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; | 131 | static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; |
132 | #endif | 132 | #endif |
133 | module_param_array(pardev, charp, NULL, 0); | 133 | module_param_array(pardev, charp, NULL, 0); |
134 | MODULE_PARM_DESC(pardev, "pardev: where to search for\n\ | 134 | MODULE_PARM_DESC(pardev, "pardev: where to search for\n\ |
135 | \teach camera. 'aggressive' means brute-force search.\n\ | 135 | \teach camera. 'aggressive' means brute-force search.\n\ |
136 | \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\ | 136 | \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\ |
137 | \tcam 1 to parport3 and search every parport for cam 2 etc..."); | 137 | \tcam 1 to parport3 and search every parport for cam 2 etc..."); |
138 | 138 | ||
139 | static int parmode; | 139 | static int parmode; |
140 | module_param(parmode, int, 0); | 140 | module_param(parmode, int, 0); |
141 | MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); | 141 | MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); |
142 | 142 | ||
143 | static int video_nr = -1; | 143 | static int video_nr = -1; |
144 | module_param(video_nr, int, 0); | 144 | module_param(video_nr, int, 0); |
145 | 145 | ||
146 | /* | 146 | /* |
147 | * Private data | 147 | * Private data |
148 | */ | 148 | */ |
149 | 149 | ||
150 | static struct w9966_dev w9966_cams[W9966_MAXCAMS]; | 150 | static struct w9966_dev w9966_cams[W9966_MAXCAMS]; |
151 | 151 | ||
152 | /* | 152 | /* |
153 | * Private function declares | 153 | * Private function declares |
154 | */ | 154 | */ |
155 | 155 | ||
156 | static inline void w9966_setState(struct w9966_dev* cam, int mask, int val); | 156 | static inline void w9966_setState(struct w9966_dev* cam, int mask, int val); |
157 | static inline int w9966_getState(struct w9966_dev* cam, int mask, int val); | 157 | static inline int w9966_getState(struct w9966_dev* cam, int mask, int val); |
158 | static inline void w9966_pdev_claim(struct w9966_dev *vdev); | 158 | static inline void w9966_pdev_claim(struct w9966_dev *vdev); |
159 | static inline void w9966_pdev_release(struct w9966_dev *vdev); | 159 | static inline void w9966_pdev_release(struct w9966_dev *vdev); |
160 | 160 | ||
161 | static int w9966_rReg(struct w9966_dev* cam, int reg); | 161 | static int w9966_rReg(struct w9966_dev* cam, int reg); |
162 | static int w9966_wReg(struct w9966_dev* cam, int reg, int data); | 162 | static int w9966_wReg(struct w9966_dev* cam, int reg, int data); |
163 | #if 0 | 163 | #if 0 |
164 | static int w9966_rReg_i2c(struct w9966_dev* cam, int reg); | 164 | static int w9966_rReg_i2c(struct w9966_dev* cam, int reg); |
165 | #endif | 165 | #endif |
166 | static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data); | 166 | static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data); |
167 | static int w9966_findlen(int near, int size, int maxlen); | 167 | static int w9966_findlen(int near, int size, int maxlen); |
168 | static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor); | 168 | static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor); |
169 | static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h); | 169 | static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h); |
170 | 170 | ||
171 | static int w9966_init(struct w9966_dev* cam, struct parport* port); | 171 | static int w9966_init(struct w9966_dev* cam, struct parport* port); |
172 | static void w9966_term(struct w9966_dev* cam); | 172 | static void w9966_term(struct w9966_dev* cam); |
173 | 173 | ||
174 | static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state); | 174 | static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state); |
175 | static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state); | 175 | static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state); |
176 | static inline int w9966_i2c_getsda(struct w9966_dev* cam); | 176 | static inline int w9966_i2c_getsda(struct w9966_dev* cam); |
177 | static inline int w9966_i2c_getscl(struct w9966_dev* cam); | 177 | static inline int w9966_i2c_getscl(struct w9966_dev* cam); |
178 | static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); | 178 | static int w9966_i2c_wbyte(struct w9966_dev* cam, int data); |
179 | #if 0 | 179 | #if 0 |
180 | static int w9966_i2c_rbyte(struct w9966_dev* cam); | 180 | static int w9966_i2c_rbyte(struct w9966_dev* cam); |
181 | #endif | 181 | #endif |
182 | 182 | ||
183 | static long w9966_v4l_ioctl(struct file *file, | 183 | static long w9966_v4l_ioctl(struct file *file, |
184 | unsigned int cmd, unsigned long arg); | 184 | unsigned int cmd, unsigned long arg); |
185 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, | 185 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, |
186 | size_t count, loff_t *ppos); | 186 | size_t count, loff_t *ppos); |
187 | 187 | ||
188 | static int w9966_exclusive_open(struct file *file) | 188 | static int w9966_exclusive_open(struct file *file) |
189 | { | 189 | { |
190 | struct w9966_dev *cam = video_drvdata(file); | 190 | struct w9966_dev *cam = video_drvdata(file); |
191 | 191 | ||
192 | return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0; | 192 | return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0; |
193 | } | 193 | } |
194 | 194 | ||
195 | static int w9966_exclusive_release(struct file *file) | 195 | static int w9966_exclusive_release(struct file *file) |
196 | { | 196 | { |
197 | struct w9966_dev *cam = video_drvdata(file); | 197 | struct w9966_dev *cam = video_drvdata(file); |
198 | 198 | ||
199 | clear_bit(0, &cam->in_use); | 199 | clear_bit(0, &cam->in_use); |
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
203 | static const struct v4l2_file_operations w9966_fops = { | 203 | static const struct v4l2_file_operations w9966_fops = { |
204 | .owner = THIS_MODULE, | 204 | .owner = THIS_MODULE, |
205 | .open = w9966_exclusive_open, | 205 | .open = w9966_exclusive_open, |
206 | .release = w9966_exclusive_release, | 206 | .release = w9966_exclusive_release, |
207 | .ioctl = w9966_v4l_ioctl, | 207 | .ioctl = w9966_v4l_ioctl, |
208 | .read = w9966_v4l_read, | 208 | .read = w9966_v4l_read, |
209 | }; | 209 | }; |
210 | static struct video_device w9966_template = { | 210 | static struct video_device w9966_template = { |
211 | .name = W9966_DRIVERNAME, | 211 | .name = W9966_DRIVERNAME, |
212 | .fops = &w9966_fops, | 212 | .fops = &w9966_fops, |
213 | .release = video_device_release_empty, | 213 | .release = video_device_release_empty, |
214 | }; | 214 | }; |
215 | 215 | ||
216 | /* | 216 | /* |
217 | * Private function defines | 217 | * Private function defines |
218 | */ | 218 | */ |
219 | 219 | ||
220 | 220 | ||
221 | // Set camera phase flags, so we know what to uninit when terminating | 221 | // Set camera phase flags, so we know what to uninit when terminating |
222 | static inline void w9966_setState(struct w9966_dev* cam, int mask, int val) | 222 | static inline void w9966_setState(struct w9966_dev* cam, int mask, int val) |
223 | { | 223 | { |
224 | cam->dev_state = (cam->dev_state & ~mask) ^ val; | 224 | cam->dev_state = (cam->dev_state & ~mask) ^ val; |
225 | } | 225 | } |
226 | 226 | ||
227 | // Get camera phase flags | 227 | // Get camera phase flags |
228 | static inline int w9966_getState(struct w9966_dev* cam, int mask, int val) | 228 | static inline int w9966_getState(struct w9966_dev* cam, int mask, int val) |
229 | { | 229 | { |
230 | return ((cam->dev_state & mask) == val); | 230 | return ((cam->dev_state & mask) == val); |
231 | } | 231 | } |
232 | 232 | ||
233 | // Claim parport for ourself | 233 | // Claim parport for ourself |
234 | static inline void w9966_pdev_claim(struct w9966_dev* cam) | 234 | static inline void w9966_pdev_claim(struct w9966_dev* cam) |
235 | { | 235 | { |
236 | if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) | 236 | if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) |
237 | return; | 237 | return; |
238 | parport_claim_or_block(cam->pdev); | 238 | parport_claim_or_block(cam->pdev); |
239 | w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); | 239 | w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); |
240 | } | 240 | } |
241 | 241 | ||
242 | // Release parport for others to use | 242 | // Release parport for others to use |
243 | static inline void w9966_pdev_release(struct w9966_dev* cam) | 243 | static inline void w9966_pdev_release(struct w9966_dev* cam) |
244 | { | 244 | { |
245 | if (w9966_getState(cam, W9966_STATE_CLAIMED, 0)) | 245 | if (w9966_getState(cam, W9966_STATE_CLAIMED, 0)) |
246 | return; | 246 | return; |
247 | parport_release(cam->pdev); | 247 | parport_release(cam->pdev); |
248 | w9966_setState(cam, W9966_STATE_CLAIMED, 0); | 248 | w9966_setState(cam, W9966_STATE_CLAIMED, 0); |
249 | } | 249 | } |
250 | 250 | ||
251 | // Read register from W9966 interface-chip | 251 | // Read register from W9966 interface-chip |
252 | // Expects a claimed pdev | 252 | // Expects a claimed pdev |
253 | // -1 on error, else register data (byte) | 253 | // -1 on error, else register data (byte) |
254 | static int w9966_rReg(struct w9966_dev* cam, int reg) | 254 | static int w9966_rReg(struct w9966_dev* cam, int reg) |
255 | { | 255 | { |
256 | // ECP, read, regtransfer, REG, REG, REG, REG, REG | 256 | // ECP, read, regtransfer, REG, REG, REG, REG, REG |
257 | const unsigned char addr = 0x80 | (reg & 0x1f); | 257 | const unsigned char addr = 0x80 | (reg & 0x1f); |
258 | unsigned char val; | 258 | unsigned char val; |
259 | 259 | ||
260 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) | 260 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) |
261 | return -1; | 261 | return -1; |
262 | if (parport_write(cam->pport, &addr, 1) != 1) | 262 | if (parport_write(cam->pport, &addr, 1) != 1) |
263 | return -1; | 263 | return -1; |
264 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) | 264 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) |
265 | return -1; | 265 | return -1; |
266 | if (parport_read(cam->pport, &val, 1) != 1) | 266 | if (parport_read(cam->pport, &val, 1) != 1) |
267 | return -1; | 267 | return -1; |
268 | 268 | ||
269 | return val; | 269 | return val; |
270 | } | 270 | } |
271 | 271 | ||
272 | // Write register to W9966 interface-chip | 272 | // Write register to W9966 interface-chip |
273 | // Expects a claimed pdev | 273 | // Expects a claimed pdev |
274 | // -1 on error | 274 | // -1 on error |
275 | static int w9966_wReg(struct w9966_dev* cam, int reg, int data) | 275 | static int w9966_wReg(struct w9966_dev* cam, int reg, int data) |
276 | { | 276 | { |
277 | // ECP, write, regtransfer, REG, REG, REG, REG, REG | 277 | // ECP, write, regtransfer, REG, REG, REG, REG, REG |
278 | const unsigned char addr = 0xc0 | (reg & 0x1f); | 278 | const unsigned char addr = 0xc0 | (reg & 0x1f); |
279 | const unsigned char val = data; | 279 | const unsigned char val = data; |
280 | 280 | ||
281 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) | 281 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) |
282 | return -1; | 282 | return -1; |
283 | if (parport_write(cam->pport, &addr, 1) != 1) | 283 | if (parport_write(cam->pport, &addr, 1) != 1) |
284 | return -1; | 284 | return -1; |
285 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) | 285 | if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) |
286 | return -1; | 286 | return -1; |
287 | if (parport_write(cam->pport, &val, 1) != 1) | 287 | if (parport_write(cam->pport, &val, 1) != 1) |
288 | return -1; | 288 | return -1; |
289 | 289 | ||
290 | return 0; | 290 | return 0; |
291 | } | 291 | } |
292 | 292 | ||
293 | // Initialize camera device. Setup all internal flags, set a | 293 | // Initialize camera device. Setup all internal flags, set a |
294 | // default video mode, setup ccd-chip, register v4l device etc.. | 294 | // default video mode, setup ccd-chip, register v4l device etc.. |
295 | // Also used for 'probing' of hardware. | 295 | // Also used for 'probing' of hardware. |
296 | // -1 on error | 296 | // -1 on error |
297 | static int w9966_init(struct w9966_dev* cam, struct parport* port) | 297 | static int w9966_init(struct w9966_dev* cam, struct parport* port) |
298 | { | 298 | { |
299 | if (cam->dev_state != 0) | 299 | if (cam->dev_state != 0) |
300 | return -1; | 300 | return -1; |
301 | 301 | ||
302 | cam->pport = port; | 302 | cam->pport = port; |
303 | cam->brightness = 128; | 303 | cam->brightness = 128; |
304 | cam->contrast = 64; | 304 | cam->contrast = 64; |
305 | cam->color = 64; | 305 | cam->color = 64; |
306 | cam->hue = 0; | 306 | cam->hue = 0; |
307 | 307 | ||
308 | // Select requested transfer mode | 308 | // Select requested transfer mode |
309 | switch(parmode) | 309 | switch(parmode) |
310 | { | 310 | { |
311 | default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) | 311 | default: // Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) |
312 | case 0: | 312 | case 0: |
313 | if (port->modes & PARPORT_MODE_ECP) | 313 | if (port->modes & PARPORT_MODE_ECP) |
314 | cam->ppmode = IEEE1284_MODE_ECP; | 314 | cam->ppmode = IEEE1284_MODE_ECP; |
315 | else if (port->modes & PARPORT_MODE_EPP) | 315 | else if (port->modes & PARPORT_MODE_EPP) |
316 | cam->ppmode = IEEE1284_MODE_EPP; | 316 | cam->ppmode = IEEE1284_MODE_EPP; |
317 | else | 317 | else |
318 | cam->ppmode = IEEE1284_MODE_ECP; | 318 | cam->ppmode = IEEE1284_MODE_ECP; |
319 | break; | 319 | break; |
320 | case 1: // hw- or sw-ecp | 320 | case 1: // hw- or sw-ecp |
321 | cam->ppmode = IEEE1284_MODE_ECP; | 321 | cam->ppmode = IEEE1284_MODE_ECP; |
322 | break; | 322 | break; |
323 | case 2: // hw- or sw-epp | 323 | case 2: // hw- or sw-epp |
324 | cam->ppmode = IEEE1284_MODE_EPP; | 324 | cam->ppmode = IEEE1284_MODE_EPP; |
325 | break; | 325 | break; |
326 | } | 326 | } |
327 | 327 | ||
328 | // Tell the parport driver that we exists | 328 | // Tell the parport driver that we exists |
329 | cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); | 329 | cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); |
330 | if (cam->pdev == NULL) { | 330 | if (cam->pdev == NULL) { |
331 | DPRINTF("parport_register_device() failed\n"); | 331 | DPRINTF("parport_register_device() failed\n"); |
332 | return -1; | 332 | return -1; |
333 | } | 333 | } |
334 | w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); | 334 | w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); |
335 | 335 | ||
336 | w9966_pdev_claim(cam); | 336 | w9966_pdev_claim(cam); |
337 | 337 | ||
338 | // Setup a default capture mode | 338 | // Setup a default capture mode |
339 | if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { | 339 | if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { |
340 | DPRINTF("w9966_setup() failed.\n"); | 340 | DPRINTF("w9966_setup() failed.\n"); |
341 | return -1; | 341 | return -1; |
342 | } | 342 | } |
343 | 343 | ||
344 | w9966_pdev_release(cam); | 344 | w9966_pdev_release(cam); |
345 | 345 | ||
346 | // Fill in the video_device struct and register us to v4l | 346 | // Fill in the video_device struct and register us to v4l |
347 | memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device)); | 347 | memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device)); |
348 | video_set_drvdata(&cam->vdev, cam); | 348 | video_set_drvdata(&cam->vdev, cam); |
349 | 349 | ||
350 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) | 350 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) |
351 | return -1; | 351 | return -1; |
352 | 352 | ||
353 | w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); | 353 | w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); |
354 | 354 | ||
355 | // All ok | 355 | // All ok |
356 | printk( | 356 | printk( |
357 | "w9966cf: Found and initialized a webcam on %s.\n", | 357 | "w9966cf: Found and initialized a webcam on %s.\n", |
358 | cam->pport->name | 358 | cam->pport->name |
359 | ); | 359 | ); |
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | 363 | ||
364 | // Terminate everything gracefully | 364 | // Terminate everything gracefully |
365 | static void w9966_term(struct w9966_dev* cam) | 365 | static void w9966_term(struct w9966_dev* cam) |
366 | { | 366 | { |
367 | // Unregister from v4l | 367 | // Unregister from v4l |
368 | if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { | 368 | if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { |
369 | video_unregister_device(&cam->vdev); | 369 | video_unregister_device(&cam->vdev); |
370 | w9966_setState(cam, W9966_STATE_VDEV, 0); | 370 | w9966_setState(cam, W9966_STATE_VDEV, 0); |
371 | } | 371 | } |
372 | 372 | ||
373 | // Terminate from IEEE1284 mode and release pdev block | 373 | // Terminate from IEEE1284 mode and release pdev block |
374 | if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { | 374 | if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { |
375 | w9966_pdev_claim(cam); | 375 | w9966_pdev_claim(cam); |
376 | parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); | 376 | parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); |
377 | w9966_pdev_release(cam); | 377 | w9966_pdev_release(cam); |
378 | } | 378 | } |
379 | 379 | ||
380 | // Unregister from parport | 380 | // Unregister from parport |
381 | if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { | 381 | if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { |
382 | parport_unregister_device(cam->pdev); | 382 | parport_unregister_device(cam->pdev); |
383 | w9966_setState(cam, W9966_STATE_PDEV, 0); | 383 | w9966_setState(cam, W9966_STATE_PDEV, 0); |
384 | } | 384 | } |
385 | } | 385 | } |
386 | 386 | ||
387 | 387 | ||
388 | // Find a good length for capture window (used both for W and H) | 388 | // Find a good length for capture window (used both for W and H) |
389 | // A bit ugly but pretty functional. The capture length | 389 | // A bit ugly but pretty functional. The capture length |
390 | // have to match the downscale | 390 | // have to match the downscale |
391 | static int w9966_findlen(int near, int size, int maxlen) | 391 | static int w9966_findlen(int near, int size, int maxlen) |
392 | { | 392 | { |
393 | int bestlen = size; | 393 | int bestlen = size; |
394 | int besterr = abs(near - bestlen); | 394 | int besterr = abs(near - bestlen); |
395 | int len; | 395 | int len; |
396 | 396 | ||
397 | for(len = size+1;len < maxlen;len++) | 397 | for(len = size+1;len < maxlen;len++) |
398 | { | 398 | { |
399 | int err; | 399 | int err; |
400 | if ( ((64*size) %len) != 0) | 400 | if ( ((64*size) %len) != 0) |
401 | continue; | 401 | continue; |
402 | 402 | ||
403 | err = abs(near - len); | 403 | err = abs(near - len); |
404 | 404 | ||
405 | // Only continue as long as we keep getting better values | 405 | // Only continue as long as we keep getting better values |
406 | if (err > besterr) | 406 | if (err > besterr) |
407 | break; | 407 | break; |
408 | 408 | ||
409 | besterr = err; | 409 | besterr = err; |
410 | bestlen = len; | 410 | bestlen = len; |
411 | } | 411 | } |
412 | 412 | ||
413 | return bestlen; | 413 | return bestlen; |
414 | } | 414 | } |
415 | 415 | ||
416 | // Modify capture window (if necessary) | 416 | // Modify capture window (if necessary) |
417 | // and calculate downscaling | 417 | // and calculate downscaling |
418 | // Return -1 on error | 418 | // Return -1 on error |
419 | static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor) | 419 | static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor) |
420 | { | 420 | { |
421 | int maxlen = max - min; | 421 | int maxlen = max - min; |
422 | int len = *end - *beg + 1; | 422 | int len = *end - *beg + 1; |
423 | int newlen = w9966_findlen(len, size, maxlen); | 423 | int newlen = w9966_findlen(len, size, maxlen); |
424 | int err = newlen - len; | 424 | int err = newlen - len; |
425 | 425 | ||
426 | // Check for bad format | 426 | // Check for bad format |
427 | if (newlen > maxlen || newlen < size) | 427 | if (newlen > maxlen || newlen < size) |
428 | return -1; | 428 | return -1; |
429 | 429 | ||
430 | // Set factor (6 bit fixed) | 430 | // Set factor (6 bit fixed) |
431 | *factor = (64*size) / newlen; | 431 | *factor = (64*size) / newlen; |
432 | if (*factor == 64) | 432 | if (*factor == 64) |
433 | *factor = 0x00; // downscale is disabled | 433 | *factor = 0x00; // downscale is disabled |
434 | else | 434 | else |
435 | *factor |= 0x80; // set downscale-enable bit | 435 | *factor |= 0x80; // set downscale-enable bit |
436 | 436 | ||
437 | // Modify old beginning and end | 437 | // Modify old beginning and end |
438 | *beg -= err / 2; | 438 | *beg -= err / 2; |
439 | *end += err - (err / 2); | 439 | *end += err - (err / 2); |
440 | 440 | ||
441 | // Move window if outside borders | 441 | // Move window if outside borders |
442 | if (*beg < min) { | 442 | if (*beg < min) { |
443 | *end += min - *beg; | 443 | *end += min - *beg; |
444 | *beg += min - *beg; | 444 | *beg += min - *beg; |
445 | } | 445 | } |
446 | if (*end > max) { | 446 | if (*end > max) { |
447 | *beg -= *end - max; | 447 | *beg -= *end - max; |
448 | *end -= *end - max; | 448 | *end -= *end - max; |
449 | } | 449 | } |
450 | 450 | ||
451 | return 0; | 451 | return 0; |
452 | } | 452 | } |
453 | 453 | ||
454 | // Setup the cameras capture window etc. | 454 | // Setup the cameras capture window etc. |
455 | // Expects a claimed pdev | 455 | // Expects a claimed pdev |
456 | // return -1 on error | 456 | // return -1 on error |
457 | static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) | 457 | static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h) |
458 | { | 458 | { |
459 | unsigned int i; | 459 | unsigned int i; |
460 | unsigned int enh_s, enh_e; | 460 | unsigned int enh_s, enh_e; |
461 | unsigned char scale_x, scale_y; | 461 | unsigned char scale_x, scale_y; |
462 | unsigned char regs[0x1c]; | 462 | unsigned char regs[0x1c]; |
463 | unsigned char saa7111_regs[] = { | 463 | unsigned char saa7111_regs[] = { |
464 | 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, | 464 | 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, |
465 | 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, | 465 | 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, |
466 | 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 466 | 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
467 | 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 | 467 | 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 |
468 | }; | 468 | }; |
469 | 469 | ||
470 | 470 | ||
471 | if (w*h*2 > W9966_SRAMSIZE) | 471 | if (w*h*2 > W9966_SRAMSIZE) |
472 | { | 472 | { |
473 | DPRINTF("capture window exceeds SRAM size!.\n"); | 473 | DPRINTF("capture window exceeds SRAM size!.\n"); |
474 | w = 200; h = 160; // Pick default values | 474 | w = 200; h = 160; // Pick default values |
475 | } | 475 | } |
476 | 476 | ||
477 | w &= ~0x1; | 477 | w &= ~0x1; |
478 | if (w < 2) w = 2; | 478 | if (w < 2) w = 2; |
479 | if (h < 1) h = 1; | 479 | if (h < 1) h = 1; |
480 | if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W; | 480 | if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W; |
481 | if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H; | 481 | if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H; |
482 | 482 | ||
483 | cam->width = w; | 483 | cam->width = w; |
484 | cam->height = h; | 484 | cam->height = h; |
485 | 485 | ||
486 | enh_s = 0; | 486 | enh_s = 0; |
487 | enh_e = w*h*2; | 487 | enh_e = w*h*2; |
488 | 488 | ||
489 | // Modify capture window if necessary and calculate downscaling | 489 | // Modify capture window if necessary and calculate downscaling |
490 | if ( | 490 | if ( |
491 | w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || | 491 | w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || |
492 | w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0 | 492 | w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0 |
493 | ) return -1; | 493 | ) return -1; |
494 | 494 | ||
495 | DPRINTF( | 495 | DPRINTF( |
496 | "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", | 496 | "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", |
497 | w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80 | 497 | w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80 |
498 | ); | 498 | ); |
499 | 499 | ||
500 | // Setup registers | 500 | // Setup registers |
501 | regs[0x00] = 0x00; // Set normal operation | 501 | regs[0x00] = 0x00; // Set normal operation |
502 | regs[0x01] = 0x18; // Capture mode | 502 | regs[0x01] = 0x18; // Capture mode |
503 | regs[0x02] = scale_y; // V-scaling | 503 | regs[0x02] = scale_y; // V-scaling |
504 | regs[0x03] = scale_x; // H-scaling | 504 | regs[0x03] = scale_x; // H-scaling |
505 | 505 | ||
506 | // Capture window | 506 | // Capture window |
507 | regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits) | 507 | regs[0x04] = (x1 & 0x0ff); // X-start (8 low bits) |
508 | regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits) | 508 | regs[0x05] = (x1 & 0x300)>>8; // X-start (2 high bits) |
509 | regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits) | 509 | regs[0x06] = (y1 & 0x0ff); // Y-start (8 low bits) |
510 | regs[0x07] = (y1 & 0x300)>>8; // Y-start (2 high bits) | 510 | regs[0x07] = (y1 & 0x300)>>8; // Y-start (2 high bits) |
511 | regs[0x08] = (x2 & 0x0ff); // X-end (8 low bits) | 511 | regs[0x08] = (x2 & 0x0ff); // X-end (8 low bits) |
512 | regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits) | 512 | regs[0x09] = (x2 & 0x300)>>8; // X-end (2 high bits) |
513 | regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits) | 513 | regs[0x0a] = (y2 & 0x0ff); // Y-end (8 low bits) |
514 | 514 | ||
515 | regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb) | 515 | regs[0x0c] = W9966_SRAMID; // SRAM-banks (1x 128kb) |
516 | 516 | ||
517 | // Enhancement layer | 517 | // Enhancement layer |
518 | regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7) | 518 | regs[0x0d] = (enh_s& 0x000ff); // Enh. start (0-7) |
519 | regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15) | 519 | regs[0x0e] = (enh_s& 0x0ff00)>>8; // Enh. start (8-15) |
520 | regs[0x0f] = (enh_s& 0x70000)>>16; // Enh. start (16-17/18??) | 520 | regs[0x0f] = (enh_s& 0x70000)>>16; // Enh. start (16-17/18??) |
521 | regs[0x10] = (enh_e& 0x000ff); // Enh. end (0-7) | 521 | regs[0x10] = (enh_e& 0x000ff); // Enh. end (0-7) |
522 | regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15) | 522 | regs[0x11] = (enh_e& 0x0ff00)>>8; // Enh. end (8-15) |
523 | regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??) | 523 | regs[0x12] = (enh_e& 0x70000)>>16; // Enh. end (16-17/18??) |
524 | 524 | ||
525 | // Misc | 525 | // Misc |
526 | regs[0x13] = 0x40; // VEE control (raw 4:2:2) | 526 | regs[0x13] = 0x40; // VEE control (raw 4:2:2) |
527 | regs[0x17] = 0x00; // ??? | 527 | regs[0x17] = 0x00; // ??? |
528 | regs[0x18] = cam->i2c_state = 0x00; // Serial bus | 528 | regs[0x18] = cam->i2c_state = 0x00; // Serial bus |
529 | regs[0x19] = 0xff; // I/O port direction control | 529 | regs[0x19] = 0xff; // I/O port direction control |
530 | regs[0x1a] = 0xff; // I/O port data register | 530 | regs[0x1a] = 0xff; // I/O port data register |
531 | regs[0x1b] = 0x10; // ??? | 531 | regs[0x1b] = 0x10; // ??? |
532 | 532 | ||
533 | // SAA7111 chip settings | 533 | // SAA7111 chip settings |
534 | saa7111_regs[0x0a] = cam->brightness; | 534 | saa7111_regs[0x0a] = cam->brightness; |
535 | saa7111_regs[0x0b] = cam->contrast; | 535 | saa7111_regs[0x0b] = cam->contrast; |
536 | saa7111_regs[0x0c] = cam->color; | 536 | saa7111_regs[0x0c] = cam->color; |
537 | saa7111_regs[0x0d] = cam->hue; | 537 | saa7111_regs[0x0d] = cam->hue; |
538 | 538 | ||
539 | // Reset (ECP-fifo & serial-bus) | 539 | // Reset (ECP-fifo & serial-bus) |
540 | if (w9966_wReg(cam, 0x00, 0x03) == -1) | 540 | if (w9966_wReg(cam, 0x00, 0x03) == -1) |
541 | return -1; | 541 | return -1; |
542 | 542 | ||
543 | // Write regs to w9966cf chip | 543 | // Write regs to w9966cf chip |
544 | for (i = 0; i < 0x1c; i++) | 544 | for (i = 0; i < 0x1c; i++) |
545 | if (w9966_wReg(cam, i, regs[i]) == -1) | 545 | if (w9966_wReg(cam, i, regs[i]) == -1) |
546 | return -1; | 546 | return -1; |
547 | 547 | ||
548 | // Write regs to saa7111 chip | 548 | // Write regs to saa7111 chip |
549 | for (i = 0; i < 0x20; i++) | 549 | for (i = 0; i < 0x20; i++) |
550 | if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1) | 550 | if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1) |
551 | return -1; | 551 | return -1; |
552 | 552 | ||
553 | return 0; | 553 | return 0; |
554 | } | 554 | } |
555 | 555 | ||
556 | /* | 556 | /* |
557 | * Ugly and primitive i2c protocol functions | 557 | * Ugly and primitive i2c protocol functions |
558 | */ | 558 | */ |
559 | 559 | ||
560 | // Sets the data line on the i2c bus. | 560 | // Sets the data line on the i2c bus. |
561 | // Expects a claimed pdev. | 561 | // Expects a claimed pdev. |
562 | static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state) | 562 | static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state) |
563 | { | 563 | { |
564 | if (state) | 564 | if (state) |
565 | cam->i2c_state |= W9966_I2C_W_DATA; | 565 | cam->i2c_state |= W9966_I2C_W_DATA; |
566 | else | 566 | else |
567 | cam->i2c_state &= ~W9966_I2C_W_DATA; | 567 | cam->i2c_state &= ~W9966_I2C_W_DATA; |
568 | 568 | ||
569 | w9966_wReg(cam, 0x18, cam->i2c_state); | 569 | w9966_wReg(cam, 0x18, cam->i2c_state); |
570 | udelay(5); | 570 | udelay(5); |
571 | } | 571 | } |
572 | 572 | ||
573 | // Get peripheral clock line | 573 | // Get peripheral clock line |
574 | // Expects a claimed pdev. | 574 | // Expects a claimed pdev. |
575 | static inline int w9966_i2c_getscl(struct w9966_dev* cam) | 575 | static inline int w9966_i2c_getscl(struct w9966_dev* cam) |
576 | { | 576 | { |
577 | const unsigned char state = w9966_rReg(cam, 0x18); | 577 | const unsigned char state = w9966_rReg(cam, 0x18); |
578 | return ((state & W9966_I2C_R_CLOCK) > 0); | 578 | return ((state & W9966_I2C_R_CLOCK) > 0); |
579 | } | 579 | } |
580 | 580 | ||
581 | // Sets the clock line on the i2c bus. | 581 | // Sets the clock line on the i2c bus. |
582 | // Expects a claimed pdev. -1 on error | 582 | // Expects a claimed pdev. -1 on error |
583 | static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state) | 583 | static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state) |
584 | { | 584 | { |
585 | unsigned long timeout; | 585 | unsigned long timeout; |
586 | 586 | ||
587 | if (state) | 587 | if (state) |
588 | cam->i2c_state |= W9966_I2C_W_CLOCK; | 588 | cam->i2c_state |= W9966_I2C_W_CLOCK; |
589 | else | 589 | else |
590 | cam->i2c_state &= ~W9966_I2C_W_CLOCK; | 590 | cam->i2c_state &= ~W9966_I2C_W_CLOCK; |
591 | 591 | ||
592 | w9966_wReg(cam, 0x18, cam->i2c_state); | 592 | w9966_wReg(cam, 0x18, cam->i2c_state); |
593 | udelay(5); | 593 | udelay(5); |
594 | 594 | ||
595 | // we go to high, we also expect the peripheral to ack. | 595 | // we go to high, we also expect the peripheral to ack. |
596 | if (state) { | 596 | if (state) { |
597 | timeout = jiffies + 100; | 597 | timeout = jiffies + 100; |
598 | while (!w9966_i2c_getscl(cam)) { | 598 | while (!w9966_i2c_getscl(cam)) { |
599 | if (time_after(jiffies, timeout)) | 599 | if (time_after(jiffies, timeout)) |
600 | return -1; | 600 | return -1; |
601 | } | 601 | } |
602 | } | 602 | } |
603 | return 0; | 603 | return 0; |
604 | } | 604 | } |
605 | 605 | ||
606 | // Get peripheral data line | 606 | // Get peripheral data line |
607 | // Expects a claimed pdev. | 607 | // Expects a claimed pdev. |
608 | static inline int w9966_i2c_getsda(struct w9966_dev* cam) | 608 | static inline int w9966_i2c_getsda(struct w9966_dev* cam) |
609 | { | 609 | { |
610 | const unsigned char state = w9966_rReg(cam, 0x18); | 610 | const unsigned char state = w9966_rReg(cam, 0x18); |
611 | return ((state & W9966_I2C_R_DATA) > 0); | 611 | return ((state & W9966_I2C_R_DATA) > 0); |
612 | } | 612 | } |
613 | 613 | ||
614 | // Write a byte with ack to the i2c bus. | 614 | // Write a byte with ack to the i2c bus. |
615 | // Expects a claimed pdev. -1 on error | 615 | // Expects a claimed pdev. -1 on error |
616 | static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) | 616 | static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) |
617 | { | 617 | { |
618 | int i; | 618 | int i; |
619 | for (i = 7; i >= 0; i--) | 619 | for (i = 7; i >= 0; i--) |
620 | { | 620 | { |
621 | w9966_i2c_setsda(cam, (data >> i) & 0x01); | 621 | w9966_i2c_setsda(cam, (data >> i) & 0x01); |
622 | 622 | ||
623 | if (w9966_i2c_setscl(cam, 1) == -1) | 623 | if (w9966_i2c_setscl(cam, 1) == -1) |
624 | return -1; | 624 | return -1; |
625 | w9966_i2c_setscl(cam, 0); | 625 | w9966_i2c_setscl(cam, 0); |
626 | } | 626 | } |
627 | 627 | ||
628 | w9966_i2c_setsda(cam, 1); | 628 | w9966_i2c_setsda(cam, 1); |
629 | 629 | ||
630 | if (w9966_i2c_setscl(cam, 1) == -1) | 630 | if (w9966_i2c_setscl(cam, 1) == -1) |
631 | return -1; | 631 | return -1; |
632 | w9966_i2c_setscl(cam, 0); | 632 | w9966_i2c_setscl(cam, 0); |
633 | 633 | ||
634 | return 0; | 634 | return 0; |
635 | } | 635 | } |
636 | 636 | ||
637 | // Read a data byte with ack from the i2c-bus | 637 | // Read a data byte with ack from the i2c-bus |
638 | // Expects a claimed pdev. -1 on error | 638 | // Expects a claimed pdev. -1 on error |
639 | #if 0 | 639 | #if 0 |
640 | static int w9966_i2c_rbyte(struct w9966_dev* cam) | 640 | static int w9966_i2c_rbyte(struct w9966_dev* cam) |
641 | { | 641 | { |
642 | unsigned char data = 0x00; | 642 | unsigned char data = 0x00; |
643 | int i; | 643 | int i; |
644 | 644 | ||
645 | w9966_i2c_setsda(cam, 1); | 645 | w9966_i2c_setsda(cam, 1); |
646 | 646 | ||
647 | for (i = 0; i < 8; i++) | 647 | for (i = 0; i < 8; i++) |
648 | { | 648 | { |
649 | if (w9966_i2c_setscl(cam, 1) == -1) | 649 | if (w9966_i2c_setscl(cam, 1) == -1) |
650 | return -1; | 650 | return -1; |
651 | data = data << 1; | 651 | data = data << 1; |
652 | if (w9966_i2c_getsda(cam)) | 652 | if (w9966_i2c_getsda(cam)) |
653 | data |= 0x01; | 653 | data |= 0x01; |
654 | 654 | ||
655 | w9966_i2c_setscl(cam, 0); | 655 | w9966_i2c_setscl(cam, 0); |
656 | } | 656 | } |
657 | return data; | 657 | return data; |
658 | } | 658 | } |
659 | #endif | 659 | #endif |
660 | 660 | ||
661 | // Read a register from the i2c device. | 661 | // Read a register from the i2c device. |
662 | // Expects claimed pdev. -1 on error | 662 | // Expects claimed pdev. -1 on error |
663 | #if 0 | 663 | #if 0 |
664 | static int w9966_rReg_i2c(struct w9966_dev* cam, int reg) | 664 | static int w9966_rReg_i2c(struct w9966_dev* cam, int reg) |
665 | { | 665 | { |
666 | int data; | 666 | int data; |
667 | 667 | ||
668 | w9966_i2c_setsda(cam, 0); | 668 | w9966_i2c_setsda(cam, 0); |
669 | w9966_i2c_setscl(cam, 0); | 669 | w9966_i2c_setscl(cam, 0); |
670 | 670 | ||
671 | if ( | 671 | if ( |
672 | w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || | 672 | w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || |
673 | w9966_i2c_wbyte(cam, reg) == -1 | 673 | w9966_i2c_wbyte(cam, reg) == -1 |
674 | ) | 674 | ) |
675 | return -1; | 675 | return -1; |
676 | 676 | ||
677 | w9966_i2c_setsda(cam, 1); | 677 | w9966_i2c_setsda(cam, 1); |
678 | if (w9966_i2c_setscl(cam, 1) == -1) | 678 | if (w9966_i2c_setscl(cam, 1) == -1) |
679 | return -1; | 679 | return -1; |
680 | w9966_i2c_setsda(cam, 0); | 680 | w9966_i2c_setsda(cam, 0); |
681 | w9966_i2c_setscl(cam, 0); | 681 | w9966_i2c_setscl(cam, 0); |
682 | 682 | ||
683 | if ( | 683 | if ( |
684 | w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 || | 684 | w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 || |
685 | (data = w9966_i2c_rbyte(cam)) == -1 | 685 | (data = w9966_i2c_rbyte(cam)) == -1 |
686 | ) | 686 | ) |
687 | return -1; | 687 | return -1; |
688 | 688 | ||
689 | w9966_i2c_setsda(cam, 0); | 689 | w9966_i2c_setsda(cam, 0); |
690 | 690 | ||
691 | if (w9966_i2c_setscl(cam, 1) == -1) | 691 | if (w9966_i2c_setscl(cam, 1) == -1) |
692 | return -1; | 692 | return -1; |
693 | w9966_i2c_setsda(cam, 1); | 693 | w9966_i2c_setsda(cam, 1); |
694 | 694 | ||
695 | return data; | 695 | return data; |
696 | } | 696 | } |
697 | #endif | 697 | #endif |
698 | 698 | ||
699 | // Write a register to the i2c device. | 699 | // Write a register to the i2c device. |
700 | // Expects claimed pdev. -1 on error | 700 | // Expects claimed pdev. -1 on error |
701 | static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) | 701 | static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) |
702 | { | 702 | { |
703 | w9966_i2c_setsda(cam, 0); | 703 | w9966_i2c_setsda(cam, 0); |
704 | w9966_i2c_setscl(cam, 0); | 704 | w9966_i2c_setscl(cam, 0); |
705 | 705 | ||
706 | if ( | 706 | if ( |
707 | w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || | 707 | w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || |
708 | w9966_i2c_wbyte(cam, reg) == -1 || | 708 | w9966_i2c_wbyte(cam, reg) == -1 || |
709 | w9966_i2c_wbyte(cam, data) == -1 | 709 | w9966_i2c_wbyte(cam, data) == -1 |
710 | ) | 710 | ) |
711 | return -1; | 711 | return -1; |
712 | 712 | ||
713 | w9966_i2c_setsda(cam, 0); | 713 | w9966_i2c_setsda(cam, 0); |
714 | if (w9966_i2c_setscl(cam, 1) == -1) | 714 | if (w9966_i2c_setscl(cam, 1) == -1) |
715 | return -1; | 715 | return -1; |
716 | 716 | ||
717 | w9966_i2c_setsda(cam, 1); | 717 | w9966_i2c_setsda(cam, 1); |
718 | 718 | ||
719 | return 0; | 719 | return 0; |
720 | } | 720 | } |
721 | 721 | ||
722 | /* | 722 | /* |
723 | * Video4linux interfacing | 723 | * Video4linux interfacing |
724 | */ | 724 | */ |
725 | 725 | ||
726 | static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 726 | static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) |
727 | { | 727 | { |
728 | struct w9966_dev *cam = video_drvdata(file); | 728 | struct w9966_dev *cam = video_drvdata(file); |
729 | 729 | ||
730 | switch(cmd) | 730 | switch(cmd) |
731 | { | 731 | { |
732 | case VIDIOCGCAP: | 732 | case VIDIOCGCAP: |
733 | { | 733 | { |
734 | static struct video_capability vcap = { | 734 | static struct video_capability vcap = { |
735 | .name = W9966_DRIVERNAME, | 735 | .name = W9966_DRIVERNAME, |
736 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, | 736 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, |
737 | .channels = 1, | 737 | .channels = 1, |
738 | .maxwidth = W9966_WND_MAX_W, | 738 | .maxwidth = W9966_WND_MAX_W, |
739 | .maxheight = W9966_WND_MAX_H, | 739 | .maxheight = W9966_WND_MAX_H, |
740 | .minwidth = 2, | 740 | .minwidth = 2, |
741 | .minheight = 1, | 741 | .minheight = 1, |
742 | }; | 742 | }; |
743 | struct video_capability *cap = arg; | 743 | struct video_capability *cap = arg; |
744 | *cap = vcap; | 744 | *cap = vcap; |
745 | return 0; | 745 | return 0; |
746 | } | 746 | } |
747 | case VIDIOCGCHAN: | 747 | case VIDIOCGCHAN: |
748 | { | 748 | { |
749 | struct video_channel *vch = arg; | 749 | struct video_channel *vch = arg; |
750 | if(vch->channel != 0) // We only support one channel (#0) | 750 | if(vch->channel != 0) // We only support one channel (#0) |
751 | return -EINVAL; | 751 | return -EINVAL; |
752 | memset(vch,0,sizeof(*vch)); | 752 | memset(vch,0,sizeof(*vch)); |
753 | strcpy(vch->name, "CCD-input"); | 753 | strcpy(vch->name, "CCD-input"); |
754 | vch->type = VIDEO_TYPE_CAMERA; | 754 | vch->type = VIDEO_TYPE_CAMERA; |
755 | return 0; | 755 | return 0; |
756 | } | 756 | } |
757 | case VIDIOCSCHAN: | 757 | case VIDIOCSCHAN: |
758 | { | 758 | { |
759 | struct video_channel *vch = arg; | 759 | struct video_channel *vch = arg; |
760 | if(vch->channel != 0) | 760 | if(vch->channel != 0) |
761 | return -EINVAL; | 761 | return -EINVAL; |
762 | return 0; | 762 | return 0; |
763 | } | 763 | } |
764 | case VIDIOCGTUNER: | 764 | case VIDIOCGTUNER: |
765 | { | 765 | { |
766 | struct video_tuner *vtune = arg; | 766 | struct video_tuner *vtune = arg; |
767 | if(vtune->tuner != 0) | 767 | if(vtune->tuner != 0) |
768 | return -EINVAL; | 768 | return -EINVAL; |
769 | strcpy(vtune->name, "no tuner"); | 769 | strcpy(vtune->name, "no tuner"); |
770 | vtune->rangelow = 0; | 770 | vtune->rangelow = 0; |
771 | vtune->rangehigh = 0; | 771 | vtune->rangehigh = 0; |
772 | vtune->flags = VIDEO_TUNER_NORM; | 772 | vtune->flags = VIDEO_TUNER_NORM; |
773 | vtune->mode = VIDEO_MODE_AUTO; | 773 | vtune->mode = VIDEO_MODE_AUTO; |
774 | vtune->signal = 0xffff; | 774 | vtune->signal = 0xffff; |
775 | return 0; | 775 | return 0; |
776 | } | 776 | } |
777 | case VIDIOCSTUNER: | 777 | case VIDIOCSTUNER: |
778 | { | 778 | { |
779 | struct video_tuner *vtune = arg; | 779 | struct video_tuner *vtune = arg; |
780 | if (vtune->tuner != 0) | 780 | if (vtune->tuner != 0) |
781 | return -EINVAL; | 781 | return -EINVAL; |
782 | if (vtune->mode != VIDEO_MODE_AUTO) | 782 | if (vtune->mode != VIDEO_MODE_AUTO) |
783 | return -EINVAL; | 783 | return -EINVAL; |
784 | return 0; | 784 | return 0; |
785 | } | 785 | } |
786 | case VIDIOCGPICT: | 786 | case VIDIOCGPICT: |
787 | { | 787 | { |
788 | struct video_picture vpic = { | 788 | struct video_picture vpic = { |
789 | cam->brightness << 8, // brightness | 789 | cam->brightness << 8, // brightness |
790 | (cam->hue + 128) << 8, // hue | 790 | (cam->hue + 128) << 8, // hue |
791 | cam->color << 9, // color | 791 | cam->color << 9, // color |
792 | cam->contrast << 9, // contrast | 792 | cam->contrast << 9, // contrast |
793 | 0x8000, // whiteness | 793 | 0x8000, // whiteness |
794 | 16, VIDEO_PALETTE_YUV422// bpp, palette format | 794 | 16, VIDEO_PALETTE_YUV422// bpp, palette format |
795 | }; | 795 | }; |
796 | struct video_picture *pic = arg; | 796 | struct video_picture *pic = arg; |
797 | *pic = vpic; | 797 | *pic = vpic; |
798 | return 0; | 798 | return 0; |
799 | } | 799 | } |
800 | case VIDIOCSPICT: | 800 | case VIDIOCSPICT: |
801 | { | 801 | { |
802 | struct video_picture *vpic = arg; | 802 | struct video_picture *vpic = arg; |
803 | if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV)) | 803 | if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV)) |
804 | return -EINVAL; | 804 | return -EINVAL; |
805 | 805 | ||
806 | cam->brightness = vpic->brightness >> 8; | 806 | cam->brightness = vpic->brightness >> 8; |
807 | cam->hue = (vpic->hue >> 8) - 128; | 807 | cam->hue = (vpic->hue >> 8) - 128; |
808 | cam->color = vpic->colour >> 9; | 808 | cam->color = vpic->colour >> 9; |
809 | cam->contrast = vpic->contrast >> 9; | 809 | cam->contrast = vpic->contrast >> 9; |
810 | 810 | ||
811 | w9966_pdev_claim(cam); | 811 | w9966_pdev_claim(cam); |
812 | 812 | ||
813 | if ( | 813 | if ( |
814 | w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 || | 814 | w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 || |
815 | w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 || | 815 | w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 || |
816 | w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 || | 816 | w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 || |
817 | w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1 | 817 | w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1 |
818 | ) { | 818 | ) { |
819 | w9966_pdev_release(cam); | 819 | w9966_pdev_release(cam); |
820 | return -EIO; | 820 | return -EIO; |
821 | } | 821 | } |
822 | 822 | ||
823 | w9966_pdev_release(cam); | 823 | w9966_pdev_release(cam); |
824 | return 0; | 824 | return 0; |
825 | } | 825 | } |
826 | case VIDIOCSWIN: | 826 | case VIDIOCSWIN: |
827 | { | 827 | { |
828 | int ret; | 828 | int ret; |
829 | struct video_window *vwin = arg; | 829 | struct video_window *vwin = arg; |
830 | 830 | ||
831 | if (vwin->flags != 0) | 831 | if (vwin->flags != 0) |
832 | return -EINVAL; | 832 | return -EINVAL; |
833 | if (vwin->clipcount != 0) | 833 | if (vwin->clipcount != 0) |
834 | return -EINVAL; | 834 | return -EINVAL; |
835 | if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W) | 835 | if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W) |
836 | return -EINVAL; | 836 | return -EINVAL; |
837 | if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H) | 837 | if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H) |
838 | return -EINVAL; | 838 | return -EINVAL; |
839 | 839 | ||
840 | // Update camera regs | 840 | // Update camera regs |
841 | w9966_pdev_claim(cam); | 841 | w9966_pdev_claim(cam); |
842 | ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height); | 842 | ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height); |
843 | w9966_pdev_release(cam); | 843 | w9966_pdev_release(cam); |
844 | 844 | ||
845 | if (ret != 0) { | 845 | if (ret != 0) { |
846 | DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); | 846 | DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n"); |
847 | return -EIO; | 847 | return -EIO; |
848 | } | 848 | } |
849 | 849 | ||
850 | return 0; | 850 | return 0; |
851 | } | 851 | } |
852 | case VIDIOCGWIN: | 852 | case VIDIOCGWIN: |
853 | { | 853 | { |
854 | struct video_window *vwin = arg; | 854 | struct video_window *vwin = arg; |
855 | memset(vwin, 0, sizeof(*vwin)); | 855 | memset(vwin, 0, sizeof(*vwin)); |
856 | vwin->width = cam->width; | 856 | vwin->width = cam->width; |
857 | vwin->height = cam->height; | 857 | vwin->height = cam->height; |
858 | return 0; | 858 | return 0; |
859 | } | 859 | } |
860 | // Unimplemented | 860 | // Unimplemented |
861 | case VIDIOCCAPTURE: | 861 | case VIDIOCCAPTURE: |
862 | case VIDIOCGFBUF: | 862 | case VIDIOCGFBUF: |
863 | case VIDIOCSFBUF: | 863 | case VIDIOCSFBUF: |
864 | case VIDIOCKEY: | 864 | case VIDIOCKEY: |
865 | case VIDIOCGFREQ: | 865 | case VIDIOCGFREQ: |
866 | case VIDIOCSFREQ: | 866 | case VIDIOCSFREQ: |
867 | case VIDIOCGAUDIO: | 867 | case VIDIOCGAUDIO: |
868 | case VIDIOCSAUDIO: | 868 | case VIDIOCSAUDIO: |
869 | return -EINVAL; | 869 | return -EINVAL; |
870 | default: | 870 | default: |
871 | return -ENOIOCTLCMD; | 871 | return -ENOIOCTLCMD; |
872 | } | 872 | } |
873 | return 0; | 873 | return 0; |
874 | } | 874 | } |
875 | 875 | ||
876 | static long w9966_v4l_ioctl(struct file *file, | 876 | static long w9966_v4l_ioctl(struct file *file, |
877 | unsigned int cmd, unsigned long arg) | 877 | unsigned int cmd, unsigned long arg) |
878 | { | 878 | { |
879 | return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl); | 879 | return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl); |
880 | } | 880 | } |
881 | 881 | ||
882 | // Capture data | 882 | // Capture data |
883 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, | 883 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, |
884 | size_t count, loff_t *ppos) | 884 | size_t count, loff_t *ppos) |
885 | { | 885 | { |
886 | struct w9966_dev *cam = video_drvdata(file); | 886 | struct w9966_dev *cam = video_drvdata(file); |
887 | unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 | 887 | unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 |
888 | unsigned char __user *dest = (unsigned char __user *)buf; | 888 | unsigned char __user *dest = (unsigned char __user *)buf; |
889 | unsigned long dleft = count; | 889 | unsigned long dleft = count; |
890 | unsigned char *tbuf; | 890 | unsigned char *tbuf; |
891 | 891 | ||
892 | // Why would anyone want more than this?? | 892 | // Why would anyone want more than this?? |
893 | if (count > cam->width * cam->height * 2) | 893 | if (count > cam->width * cam->height * 2) |
894 | return -EINVAL; | 894 | return -EINVAL; |
895 | 895 | ||
896 | w9966_pdev_claim(cam); | 896 | w9966_pdev_claim(cam); |
897 | w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer | 897 | w9966_wReg(cam, 0x00, 0x02); // Reset ECP-FIFO buffer |
898 | w9966_wReg(cam, 0x00, 0x00); // Return to normal operation | 898 | w9966_wReg(cam, 0x00, 0x00); // Return to normal operation |
899 | w9966_wReg(cam, 0x01, 0x98); // Enable capture | 899 | w9966_wReg(cam, 0x01, 0x98); // Enable capture |
900 | 900 | ||
901 | // write special capture-addr and negotiate into data transfer | 901 | // write special capture-addr and negotiate into data transfer |
902 | if ( | 902 | if ( |
903 | (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )|| | 903 | (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0 )|| |
904 | (parport_write(cam->pport, &addr, 1) != 1 )|| | 904 | (parport_write(cam->pport, &addr, 1) != 1 )|| |
905 | (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 ) | 905 | (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0 ) |
906 | ) { | 906 | ) { |
907 | w9966_pdev_release(cam); | 907 | w9966_pdev_release(cam); |
908 | return -EFAULT; | 908 | return -EFAULT; |
909 | } | 909 | } |
910 | 910 | ||
911 | tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); | 911 | tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); |
912 | if (tbuf == NULL) { | 912 | if (tbuf == NULL) { |
913 | count = -ENOMEM; | 913 | count = -ENOMEM; |
914 | goto out; | 914 | goto out; |
915 | } | 915 | } |
916 | 916 | ||
917 | while(dleft > 0) | 917 | while(dleft > 0) |
918 | { | 918 | { |
919 | unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; | 919 | unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; |
920 | 920 | ||
921 | if (parport_read(cam->pport, tbuf, tsize) < tsize) { | 921 | if (parport_read(cam->pport, tbuf, tsize) < tsize) { |
922 | count = -EFAULT; | 922 | count = -EFAULT; |
923 | goto out; | 923 | goto out; |
924 | } | 924 | } |
925 | if (copy_to_user(dest, tbuf, tsize) != 0) { | 925 | if (copy_to_user(dest, tbuf, tsize) != 0) { |
926 | count = -EFAULT; | 926 | count = -EFAULT; |
927 | goto out; | 927 | goto out; |
928 | } | 928 | } |
929 | dest += tsize; | 929 | dest += tsize; |
930 | dleft -= tsize; | 930 | dleft -= tsize; |
931 | } | 931 | } |
932 | 932 | ||
933 | w9966_wReg(cam, 0x01, 0x18); // Disable capture | 933 | w9966_wReg(cam, 0x01, 0x18); // Disable capture |
934 | 934 | ||
935 | out: | 935 | out: |
936 | kfree(tbuf); | 936 | kfree(tbuf); |
937 | w9966_pdev_release(cam); | 937 | w9966_pdev_release(cam); |
938 | 938 | ||
939 | return count; | 939 | return count; |
940 | } | 940 | } |
941 | 941 | ||
942 | 942 | ||
943 | // Called once for every parport on init | 943 | // Called once for every parport on init |
944 | static void w9966_attach(struct parport *port) | 944 | static void w9966_attach(struct parport *port) |
945 | { | 945 | { |
946 | int i; | 946 | int i; |
947 | 947 | ||
948 | for (i = 0; i < W9966_MAXCAMS; i++) | 948 | for (i = 0; i < W9966_MAXCAMS; i++) |
949 | { | 949 | { |
950 | if (w9966_cams[i].dev_state != 0) // Cam is already assigned | 950 | if (w9966_cams[i].dev_state != 0) // Cam is already assigned |
951 | continue; | 951 | continue; |
952 | if ( | 952 | if ( |
953 | strcmp(pardev[i], "aggressive") == 0 || | 953 | strcmp(pardev[i], "aggressive") == 0 || |
954 | strcmp(pardev[i], port->name) == 0 | 954 | strcmp(pardev[i], port->name) == 0 |
955 | ) { | 955 | ) { |
956 | if (w9966_init(&w9966_cams[i], port) != 0) | 956 | if (w9966_init(&w9966_cams[i], port) != 0) |
957 | w9966_term(&w9966_cams[i]); | 957 | w9966_term(&w9966_cams[i]); |
958 | break; // return | 958 | break; // return |
959 | } | 959 | } |
960 | } | 960 | } |
961 | } | 961 | } |
962 | 962 | ||
963 | // Called once for every parport on termination | 963 | // Called once for every parport on termination |
964 | static void w9966_detach(struct parport *port) | 964 | static void w9966_detach(struct parport *port) |
965 | { | 965 | { |
966 | int i; | 966 | int i; |
967 | for (i = 0; i < W9966_MAXCAMS; i++) | 967 | for (i = 0; i < W9966_MAXCAMS; i++) |
968 | if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) | 968 | if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) |
969 | w9966_term(&w9966_cams[i]); | 969 | w9966_term(&w9966_cams[i]); |
970 | } | 970 | } |
971 | 971 | ||
972 | 972 | ||
973 | static struct parport_driver w9966_ppd = { | 973 | static struct parport_driver w9966_ppd = { |
974 | .name = W9966_DRIVERNAME, | 974 | .name = W9966_DRIVERNAME, |
975 | .attach = w9966_attach, | 975 | .attach = w9966_attach, |
976 | .detach = w9966_detach, | 976 | .detach = w9966_detach, |
977 | }; | 977 | }; |
978 | 978 | ||
979 | // Module entry point | 979 | // Module entry point |
980 | static int __init w9966_mod_init(void) | 980 | static int __init w9966_mod_init(void) |
981 | { | 981 | { |
982 | int i; | 982 | int i; |
983 | for (i = 0; i < W9966_MAXCAMS; i++) | 983 | for (i = 0; i < W9966_MAXCAMS; i++) |
984 | w9966_cams[i].dev_state = 0; | 984 | w9966_cams[i].dev_state = 0; |
985 | 985 | ||
986 | return parport_register_driver(&w9966_ppd); | 986 | return parport_register_driver(&w9966_ppd); |
987 | } | 987 | } |
988 | 988 | ||
989 | // Module cleanup | 989 | // Module cleanup |
990 | static void __exit w9966_mod_term(void) | 990 | static void __exit w9966_mod_term(void) |
991 | { | 991 | { |
992 | parport_unregister_driver(&w9966_ppd); | 992 | parport_unregister_driver(&w9966_ppd); |
993 | } | 993 | } |
994 | 994 | ||
995 | module_init(w9966_mod_init); | 995 | module_init(w9966_mod_init); |
996 | module_exit(w9966_mod_term); | 996 | module_exit(w9966_mod_term); |
997 | 997 |
drivers/media/video/w9968cf.c
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * | 2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * |
3 | * * | 3 | * * |
4 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | 4 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * |
5 | * * | 5 | * * |
6 | * - Memory management code from bttv driver by Ralph Metzler, * | 6 | * - Memory management code from bttv driver by Ralph Metzler, * |
7 | * Marcus Metzler and Gerd Knorr. * | 7 | * Marcus Metzler and Gerd Knorr. * |
8 | * - I2C interface to kernel, high-level image sensor control routines and * | 8 | * - I2C interface to kernel, high-level image sensor control routines and * |
9 | * some symbolic names from OV511 driver by Mark W. McClelland. * | 9 | * some symbolic names from OV511 driver by Mark W. McClelland. * |
10 | * - Low-level I2C fast write function by Piotr Czerczak. * | 10 | * - Low-level I2C fast write function by Piotr Czerczak. * |
11 | * - Low-level I2C read function by Frederic Jouault. * | 11 | * - Low-level I2C read function by Frederic Jouault. * |
12 | * * | 12 | * * |
13 | * This program is free software; you can redistribute it and/or modify * | 13 | * This program is free software; you can redistribute it and/or modify * |
14 | * it under the terms of the GNU General Public License as published by * | 14 | * it under the terms of the GNU General Public License as published by * |
15 | * the Free Software Foundation; either version 2 of the License, or * | 15 | * the Free Software Foundation; either version 2 of the License, or * |
16 | * (at your option) any later version. * | 16 | * (at your option) any later version. * |
17 | * * | 17 | * * |
18 | * This program is distributed in the hope that it will be useful, * | 18 | * This program is distributed in the hope that it will be useful, * |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
21 | * GNU General Public License for more details. * | 21 | * GNU General Public License for more details. * |
22 | * * | 22 | * * |
23 | * You should have received a copy of the GNU General Public License * | 23 | * You should have received a copy of the GNU General Public License * |
24 | * along with this program; if not, write to the Free Software * | 24 | * along with this program; if not, write to the Free Software * |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * |
26 | ***************************************************************************/ | 26 | ***************************************************************************/ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/kmod.h> | 30 | #include <linux/kmod.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/fs.h> | 32 | #include <linux/fs.h> |
33 | #include <linux/vmalloc.h> | 33 | #include <linux/vmalloc.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/mm.h> | 35 | #include <linux/mm.h> |
36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
37 | #include <linux/errno.h> | 37 | #include <linux/errno.h> |
38 | #include <linux/sched.h> | 38 | #include <linux/sched.h> |
39 | #include <linux/ioctl.h> | 39 | #include <linux/ioctl.h> |
40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
41 | #include <linux/stddef.h> | 41 | #include <linux/stddef.h> |
42 | #include <asm/page.h> | 42 | #include <asm/page.h> |
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <linux/page-flags.h> | 44 | #include <linux/page-flags.h> |
45 | #include <linux/videodev.h> | ||
45 | #include <media/v4l2-ioctl.h> | 46 | #include <media/v4l2-ioctl.h> |
46 | 47 | ||
47 | #include "w9968cf.h" | 48 | #include "w9968cf.h" |
48 | #include "w9968cf_decoder.h" | 49 | #include "w9968cf_decoder.h" |
49 | 50 | ||
50 | static struct w9968cf_vpp_t* w9968cf_vpp; | 51 | static struct w9968cf_vpp_t* w9968cf_vpp; |
51 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); | 52 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); |
52 | 53 | ||
53 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ | 54 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ |
54 | static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ | 55 | static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ |
55 | 56 | ||
56 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ | 57 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ |
57 | 58 | ||
58 | 59 | ||
59 | /**************************************************************************** | 60 | /**************************************************************************** |
60 | * Module macros and parameters * | 61 | * Module macros and parameters * |
61 | ****************************************************************************/ | 62 | ****************************************************************************/ |
62 | 63 | ||
63 | MODULE_DEVICE_TABLE(usb, winbond_id_table); | 64 | MODULE_DEVICE_TABLE(usb, winbond_id_table); |
64 | 65 | ||
65 | MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); | 66 | MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); |
66 | MODULE_DESCRIPTION(W9968CF_MODULE_NAME); | 67 | MODULE_DESCRIPTION(W9968CF_MODULE_NAME); |
67 | MODULE_VERSION(W9968CF_MODULE_VERSION); | 68 | MODULE_VERSION(W9968CF_MODULE_VERSION); |
68 | MODULE_LICENSE(W9968CF_MODULE_LICENSE); | 69 | MODULE_LICENSE(W9968CF_MODULE_LICENSE); |
69 | MODULE_SUPPORTED_DEVICE("Video"); | 70 | MODULE_SUPPORTED_DEVICE("Video"); |
70 | 71 | ||
71 | static unsigned short simcams = W9968CF_SIMCAMS; | 72 | static unsigned short simcams = W9968CF_SIMCAMS; |
72 | static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ | 73 | static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ |
73 | static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 74 | static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
74 | W9968CF_PACKET_SIZE}; | 75 | W9968CF_PACKET_SIZE}; |
75 | static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 76 | static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
76 | W9968CF_BUFFERS}; | 77 | W9968CF_BUFFERS}; |
77 | static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 78 | static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
78 | W9968CF_DOUBLE_BUFFER}; | 79 | W9968CF_DOUBLE_BUFFER}; |
79 | static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; | 80 | static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; |
80 | static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = | 81 | static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = |
81 | W9968CF_FILTER_TYPE}; | 82 | W9968CF_FILTER_TYPE}; |
82 | static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; | 83 | static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; |
83 | static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 84 | static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
84 | W9968CF_DECOMPRESSION}; | 85 | W9968CF_DECOMPRESSION}; |
85 | static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; | 86 | static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; |
86 | static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; | 87 | static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; |
87 | static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; | 88 | static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; |
88 | static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; | 89 | static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; |
89 | static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; | 90 | static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; |
90 | static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 91 | static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
91 | W9968CF_LIGHTFREQ}; | 92 | W9968CF_LIGHTFREQ}; |
92 | static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= | 93 | static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= |
93 | W9968CF_BANDINGFILTER}; | 94 | W9968CF_BANDINGFILTER}; |
94 | static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; | 95 | static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; |
95 | static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; | 96 | static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; |
96 | static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; | 97 | static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; |
97 | static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; | 98 | static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; |
98 | static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 99 | static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
99 | W9968CF_BRIGHTNESS}; | 100 | W9968CF_BRIGHTNESS}; |
100 | static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; | 101 | static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; |
101 | static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; | 102 | static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; |
102 | static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 103 | static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
103 | W9968CF_CONTRAST}; | 104 | W9968CF_CONTRAST}; |
104 | static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | 105 | static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = |
105 | W9968CF_WHITENESS}; | 106 | W9968CF_WHITENESS}; |
106 | #ifdef W9968CF_DEBUG | 107 | #ifdef W9968CF_DEBUG |
107 | static unsigned short debug = W9968CF_DEBUG_LEVEL; | 108 | static unsigned short debug = W9968CF_DEBUG_LEVEL; |
108 | static int specific_debug = W9968CF_SPECIFIC_DEBUG; | 109 | static int specific_debug = W9968CF_SPECIFIC_DEBUG; |
109 | #endif | 110 | #endif |
110 | 111 | ||
111 | static unsigned int param_nv[24]; /* number of values per parameter */ | 112 | static unsigned int param_nv[24]; /* number of values per parameter */ |
112 | 113 | ||
113 | module_param(simcams, ushort, 0644); | 114 | module_param(simcams, ushort, 0644); |
114 | module_param_array(video_nr, short, ¶m_nv[0], 0444); | 115 | module_param_array(video_nr, short, ¶m_nv[0], 0444); |
115 | module_param_array(packet_size, uint, ¶m_nv[1], 0444); | 116 | module_param_array(packet_size, uint, ¶m_nv[1], 0444); |
116 | module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); | 117 | module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); |
117 | module_param_array(double_buffer, bool, ¶m_nv[3], 0444); | 118 | module_param_array(double_buffer, bool, ¶m_nv[3], 0444); |
118 | module_param_array(clamping, bool, ¶m_nv[4], 0444); | 119 | module_param_array(clamping, bool, ¶m_nv[4], 0444); |
119 | module_param_array(filter_type, ushort, ¶m_nv[5], 0444); | 120 | module_param_array(filter_type, ushort, ¶m_nv[5], 0444); |
120 | module_param_array(largeview, bool, ¶m_nv[6], 0444); | 121 | module_param_array(largeview, bool, ¶m_nv[6], 0444); |
121 | module_param_array(decompression, ushort, ¶m_nv[7], 0444); | 122 | module_param_array(decompression, ushort, ¶m_nv[7], 0444); |
122 | module_param_array(upscaling, bool, ¶m_nv[8], 0444); | 123 | module_param_array(upscaling, bool, ¶m_nv[8], 0444); |
123 | module_param_array(force_palette, ushort, ¶m_nv[9], 0444); | 124 | module_param_array(force_palette, ushort, ¶m_nv[9], 0444); |
124 | module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); | 125 | module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); |
125 | module_param_array(autobright, bool, ¶m_nv[11], 0444); | 126 | module_param_array(autobright, bool, ¶m_nv[11], 0444); |
126 | module_param_array(autoexp, bool, ¶m_nv[12], 0444); | 127 | module_param_array(autoexp, bool, ¶m_nv[12], 0444); |
127 | module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); | 128 | module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); |
128 | module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); | 129 | module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); |
129 | module_param_array(clockdiv, short, ¶m_nv[15], 0444); | 130 | module_param_array(clockdiv, short, ¶m_nv[15], 0444); |
130 | module_param_array(backlight, bool, ¶m_nv[16], 0444); | 131 | module_param_array(backlight, bool, ¶m_nv[16], 0444); |
131 | module_param_array(mirror, bool, ¶m_nv[17], 0444); | 132 | module_param_array(mirror, bool, ¶m_nv[17], 0444); |
132 | module_param_array(monochrome, bool, ¶m_nv[18], 0444); | 133 | module_param_array(monochrome, bool, ¶m_nv[18], 0444); |
133 | module_param_array(brightness, uint, ¶m_nv[19], 0444); | 134 | module_param_array(brightness, uint, ¶m_nv[19], 0444); |
134 | module_param_array(hue, uint, ¶m_nv[20], 0444); | 135 | module_param_array(hue, uint, ¶m_nv[20], 0444); |
135 | module_param_array(colour, uint, ¶m_nv[21], 0444); | 136 | module_param_array(colour, uint, ¶m_nv[21], 0444); |
136 | module_param_array(contrast, uint, ¶m_nv[22], 0444); | 137 | module_param_array(contrast, uint, ¶m_nv[22], 0444); |
137 | module_param_array(whiteness, uint, ¶m_nv[23], 0444); | 138 | module_param_array(whiteness, uint, ¶m_nv[23], 0444); |
138 | #ifdef W9968CF_DEBUG | 139 | #ifdef W9968CF_DEBUG |
139 | module_param(debug, ushort, 0644); | 140 | module_param(debug, ushort, 0644); |
140 | module_param(specific_debug, bool, 0644); | 141 | module_param(specific_debug, bool, 0644); |
141 | #endif | 142 | #endif |
142 | 143 | ||
143 | MODULE_PARM_DESC(simcams, | 144 | MODULE_PARM_DESC(simcams, |
144 | "\n<n> Number of cameras allowed to stream simultaneously." | 145 | "\n<n> Number of cameras allowed to stream simultaneously." |
145 | "\nn may vary from 0 to " | 146 | "\nn may vary from 0 to " |
146 | __MODULE_STRING(W9968CF_MAX_DEVICES)"." | 147 | __MODULE_STRING(W9968CF_MAX_DEVICES)"." |
147 | "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." | 148 | "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." |
148 | "\n"); | 149 | "\n"); |
149 | MODULE_PARM_DESC(video_nr, | 150 | MODULE_PARM_DESC(video_nr, |
150 | "\n<-1|n[,...]> Specify V4L minor mode number." | 151 | "\n<-1|n[,...]> Specify V4L minor mode number." |
151 | "\n -1 = use next available (default)" | 152 | "\n -1 = use next available (default)" |
152 | "\n n = use minor number n (integer >= 0)" | 153 | "\n n = use minor number n (integer >= 0)" |
153 | "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) | 154 | "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) |
154 | " cameras this way." | 155 | " cameras this way." |
155 | "\nFor example:" | 156 | "\nFor example:" |
156 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | 157 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" |
157 | "\nthe second camera and use auto for the first" | 158 | "\nthe second camera and use auto for the first" |
158 | "\none and for every other camera." | 159 | "\none and for every other camera." |
159 | "\n"); | 160 | "\n"); |
160 | MODULE_PARM_DESC(packet_size, | 161 | MODULE_PARM_DESC(packet_size, |
161 | "\n<n[,...]> Specify the maximum data payload" | 162 | "\n<n[,...]> Specify the maximum data payload" |
162 | "\nsize in bytes for alternate settings, for each device." | 163 | "\nsize in bytes for alternate settings, for each device." |
163 | "\nn is scaled between 63 and 1023 " | 164 | "\nn is scaled between 63 and 1023 " |
164 | "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." | 165 | "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." |
165 | "\n"); | 166 | "\n"); |
166 | MODULE_PARM_DESC(max_buffers, | 167 | MODULE_PARM_DESC(max_buffers, |
167 | "\n<n[,...]> For advanced users." | 168 | "\n<n[,...]> For advanced users." |
168 | "\nSpecify the maximum number of video frame buffers" | 169 | "\nSpecify the maximum number of video frame buffers" |
169 | "\nto allocate for each device, from 2 to " | 170 | "\nto allocate for each device, from 2 to " |
170 | __MODULE_STRING(W9968CF_MAX_BUFFERS) | 171 | __MODULE_STRING(W9968CF_MAX_BUFFERS) |
171 | ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." | 172 | ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." |
172 | "\n"); | 173 | "\n"); |
173 | MODULE_PARM_DESC(double_buffer, | 174 | MODULE_PARM_DESC(double_buffer, |
174 | "\n<0|1[,...]> " | 175 | "\n<0|1[,...]> " |
175 | "Hardware double buffering: 0 disabled, 1 enabled." | 176 | "Hardware double buffering: 0 disabled, 1 enabled." |
176 | "\nIt should be enabled if you want smooth video output: if" | 177 | "\nIt should be enabled if you want smooth video output: if" |
177 | "\nyou obtain out of sync. video, disable it, or try to" | 178 | "\nyou obtain out of sync. video, disable it, or try to" |
178 | "\ndecrease the 'clockdiv' module parameter value." | 179 | "\ndecrease the 'clockdiv' module parameter value." |
179 | "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) | 180 | "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) |
180 | " for every device." | 181 | " for every device." |
181 | "\n"); | 182 | "\n"); |
182 | MODULE_PARM_DESC(clamping, | 183 | MODULE_PARM_DESC(clamping, |
183 | "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." | 184 | "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." |
184 | "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) | 185 | "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) |
185 | " for every device." | 186 | " for every device." |
186 | "\n"); | 187 | "\n"); |
187 | MODULE_PARM_DESC(filter_type, | 188 | MODULE_PARM_DESC(filter_type, |
188 | "\n<0|1|2[,...]> Video filter type." | 189 | "\n<0|1|2[,...]> Video filter type." |
189 | "\n0 none, 1 (1-2-1) 3-tap filter, " | 190 | "\n0 none, 1 (1-2-1) 3-tap filter, " |
190 | "2 (2-3-6-3-2) 5-tap filter." | 191 | "2 (2-3-6-3-2) 5-tap filter." |
191 | "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) | 192 | "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) |
192 | " for every device." | 193 | " for every device." |
193 | "\nThe filter is used to reduce noise and aliasing artifacts" | 194 | "\nThe filter is used to reduce noise and aliasing artifacts" |
194 | "\nproduced by the CCD or CMOS image sensor, and the scaling" | 195 | "\nproduced by the CCD or CMOS image sensor, and the scaling" |
195 | " process." | 196 | " process." |
196 | "\n"); | 197 | "\n"); |
197 | MODULE_PARM_DESC(largeview, | 198 | MODULE_PARM_DESC(largeview, |
198 | "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." | 199 | "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." |
199 | "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) | 200 | "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) |
200 | " for every device." | 201 | " for every device." |
201 | "\n"); | 202 | "\n"); |
202 | MODULE_PARM_DESC(upscaling, | 203 | MODULE_PARM_DESC(upscaling, |
203 | "\n<0|1[,...]> Software scaling (for non-compressed video):" | 204 | "\n<0|1[,...]> Software scaling (for non-compressed video):" |
204 | "\n0 disabled, 1 enabled." | 205 | "\n0 disabled, 1 enabled." |
205 | "\nDisable it if you have a slow CPU or you don't have" | 206 | "\nDisable it if you have a slow CPU or you don't have" |
206 | " enough memory." | 207 | " enough memory." |
207 | "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) | 208 | "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) |
208 | " for every device." | 209 | " for every device." |
209 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | 210 | "\nIf 'w9968cf-vpp' is not present, this parameter is" |
210 | " set to 0." | 211 | " set to 0." |
211 | "\n"); | 212 | "\n"); |
212 | MODULE_PARM_DESC(decompression, | 213 | MODULE_PARM_DESC(decompression, |
213 | "\n<0|1|2[,...]> Software video decompression:" | 214 | "\n<0|1|2[,...]> Software video decompression:" |
214 | "\n- 0 disables decompression (doesn't allow formats needing" | 215 | "\n- 0 disables decompression (doesn't allow formats needing" |
215 | " decompression)" | 216 | " decompression)" |
216 | "\n- 1 forces decompression (allows formats needing" | 217 | "\n- 1 forces decompression (allows formats needing" |
217 | " decompression only);" | 218 | " decompression only);" |
218 | "\n- 2 allows any permitted formats." | 219 | "\n- 2 allows any permitted formats." |
219 | "\nFormats supporting compressed video are YUV422P and" | 220 | "\nFormats supporting compressed video are YUV422P and" |
220 | " YUV420P/YUV420 " | 221 | " YUV420P/YUV420 " |
221 | "\nin any resolutions where both width and height are " | 222 | "\nin any resolutions where both width and height are " |
222 | "a multiple of 16." | 223 | "a multiple of 16." |
223 | "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) | 224 | "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) |
224 | " for every device." | 225 | " for every device." |
225 | "\nIf 'w9968cf-vpp' is not present, forcing decompression is " | 226 | "\nIf 'w9968cf-vpp' is not present, forcing decompression is " |
226 | "\nnot allowed; in this case this parameter is set to 2." | 227 | "\nnot allowed; in this case this parameter is set to 2." |
227 | "\n"); | 228 | "\n"); |
228 | MODULE_PARM_DESC(force_palette, | 229 | MODULE_PARM_DESC(force_palette, |
229 | "\n<0" | 230 | "\n<0" |
230 | "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) | 231 | "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) |
231 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) | 232 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) |
232 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) | 233 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) |
233 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) | 234 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) |
234 | "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) | 235 | "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) |
235 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) | 236 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) |
236 | "|" __MODULE_STRING(VIDEO_PALETTE_GREY) | 237 | "|" __MODULE_STRING(VIDEO_PALETTE_GREY) |
237 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) | 238 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) |
238 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) | 239 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) |
239 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) | 240 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) |
240 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) | 241 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) |
241 | "[,...]>" | 242 | "[,...]>" |
242 | " Force picture palette." | 243 | " Force picture palette." |
243 | "\nIn order:" | 244 | "\nIn order:" |
244 | "\n- 0 allows any of the following formats:" | 245 | "\n- 0 allows any of the following formats:" |
245 | "\n- UYVY 16 bpp - Original video, compression disabled" | 246 | "\n- UYVY 16 bpp - Original video, compression disabled" |
246 | "\n- YUV420 12 bpp - Original video, compression enabled" | 247 | "\n- YUV420 12 bpp - Original video, compression enabled" |
247 | "\n- YUV422P 16 bpp - Original video, compression enabled" | 248 | "\n- YUV422P 16 bpp - Original video, compression enabled" |
248 | "\n- YUV420P 12 bpp - Original video, compression enabled" | 249 | "\n- YUV420P 12 bpp - Original video, compression enabled" |
249 | "\n- YUVY 16 bpp - Software conversion from UYVY" | 250 | "\n- YUVY 16 bpp - Software conversion from UYVY" |
250 | "\n- YUV422 16 bpp - Software conversion from UYVY" | 251 | "\n- YUV422 16 bpp - Software conversion from UYVY" |
251 | "\n- GREY 8 bpp - Software conversion from UYVY" | 252 | "\n- GREY 8 bpp - Software conversion from UYVY" |
252 | "\n- RGB555 16 bpp - Software conversion from UYVY" | 253 | "\n- RGB555 16 bpp - Software conversion from UYVY" |
253 | "\n- RGB565 16 bpp - Software conversion from UYVY" | 254 | "\n- RGB565 16 bpp - Software conversion from UYVY" |
254 | "\n- RGB24 24 bpp - Software conversion from UYVY" | 255 | "\n- RGB24 24 bpp - Software conversion from UYVY" |
255 | "\n- RGB32 32 bpp - Software conversion from UYVY" | 256 | "\n- RGB32 32 bpp - Software conversion from UYVY" |
256 | "\nWhen not 0, this parameter will override 'decompression'." | 257 | "\nWhen not 0, this parameter will override 'decompression'." |
257 | "\nDefault value is 0 for every device." | 258 | "\nDefault value is 0 for every device." |
258 | "\nInitial palette is " | 259 | "\nInitial palette is " |
259 | __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." | 260 | __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." |
260 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | 261 | "\nIf 'w9968cf-vpp' is not present, this parameter is" |
261 | " set to 9 (UYVY)." | 262 | " set to 9 (UYVY)." |
262 | "\n"); | 263 | "\n"); |
263 | MODULE_PARM_DESC(force_rgb, | 264 | MODULE_PARM_DESC(force_rgb, |
264 | "\n<0|1[,...]> Read RGB video data instead of BGR:" | 265 | "\n<0|1[,...]> Read RGB video data instead of BGR:" |
265 | "\n 1 = use RGB component ordering." | 266 | "\n 1 = use RGB component ordering." |
266 | "\n 0 = use BGR component ordering." | 267 | "\n 0 = use BGR component ordering." |
267 | "\nThis parameter has effect when using RGBX palettes only." | 268 | "\nThis parameter has effect when using RGBX palettes only." |
268 | "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) | 269 | "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) |
269 | " for every device." | 270 | " for every device." |
270 | "\n"); | 271 | "\n"); |
271 | MODULE_PARM_DESC(autobright, | 272 | MODULE_PARM_DESC(autobright, |
272 | "\n<0|1[,...]> Image sensor automatically changes brightness:" | 273 | "\n<0|1[,...]> Image sensor automatically changes brightness:" |
273 | "\n 0 = no, 1 = yes" | 274 | "\n 0 = no, 1 = yes" |
274 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) | 275 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) |
275 | " for every device." | 276 | " for every device." |
276 | "\n"); | 277 | "\n"); |
277 | MODULE_PARM_DESC(autoexp, | 278 | MODULE_PARM_DESC(autoexp, |
278 | "\n<0|1[,...]> Image sensor automatically changes exposure:" | 279 | "\n<0|1[,...]> Image sensor automatically changes exposure:" |
279 | "\n 0 = no, 1 = yes" | 280 | "\n 0 = no, 1 = yes" |
280 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) | 281 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) |
281 | " for every device." | 282 | " for every device." |
282 | "\n"); | 283 | "\n"); |
283 | MODULE_PARM_DESC(lightfreq, | 284 | MODULE_PARM_DESC(lightfreq, |
284 | "\n<50|60[,...]> Light frequency in Hz:" | 285 | "\n<50|60[,...]> Light frequency in Hz:" |
285 | "\n 50 for European and Asian lighting," | 286 | "\n 50 for European and Asian lighting," |
286 | " 60 for American lighting." | 287 | " 60 for American lighting." |
287 | "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) | 288 | "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) |
288 | " for every device." | 289 | " for every device." |
289 | "\n"); | 290 | "\n"); |
290 | MODULE_PARM_DESC(bandingfilter, | 291 | MODULE_PARM_DESC(bandingfilter, |
291 | "\n<0|1[,...]> Banding filter to reduce effects of" | 292 | "\n<0|1[,...]> Banding filter to reduce effects of" |
292 | " fluorescent lighting:" | 293 | " fluorescent lighting:" |
293 | "\n 0 disabled, 1 enabled." | 294 | "\n 0 disabled, 1 enabled." |
294 | "\nThis filter tries to reduce the pattern of horizontal" | 295 | "\nThis filter tries to reduce the pattern of horizontal" |
295 | "\nlight/dark bands caused by some (usually fluorescent)" | 296 | "\nlight/dark bands caused by some (usually fluorescent)" |
296 | " lighting." | 297 | " lighting." |
297 | "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) | 298 | "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) |
298 | " for every device." | 299 | " for every device." |
299 | "\n"); | 300 | "\n"); |
300 | MODULE_PARM_DESC(clockdiv, | 301 | MODULE_PARM_DESC(clockdiv, |
301 | "\n<-1|n[,...]> " | 302 | "\n<-1|n[,...]> " |
302 | "Force pixel clock divisor to a specific value (for experts):" | 303 | "Force pixel clock divisor to a specific value (for experts):" |
303 | "\n n may vary from 0 to 127." | 304 | "\n n may vary from 0 to 127." |
304 | "\n -1 for automatic value." | 305 | "\n -1 for automatic value." |
305 | "\nSee also the 'double_buffer' module parameter." | 306 | "\nSee also the 'double_buffer' module parameter." |
306 | "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) | 307 | "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) |
307 | " for every device." | 308 | " for every device." |
308 | "\n"); | 309 | "\n"); |
309 | MODULE_PARM_DESC(backlight, | 310 | MODULE_PARM_DESC(backlight, |
310 | "\n<0|1[,...]> Objects are lit from behind:" | 311 | "\n<0|1[,...]> Objects are lit from behind:" |
311 | "\n 0 = no, 1 = yes" | 312 | "\n 0 = no, 1 = yes" |
312 | "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) | 313 | "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) |
313 | " for every device." | 314 | " for every device." |
314 | "\n"); | 315 | "\n"); |
315 | MODULE_PARM_DESC(mirror, | 316 | MODULE_PARM_DESC(mirror, |
316 | "\n<0|1[,...]> Reverse image horizontally:" | 317 | "\n<0|1[,...]> Reverse image horizontally:" |
317 | "\n 0 = no, 1 = yes" | 318 | "\n 0 = no, 1 = yes" |
318 | "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) | 319 | "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) |
319 | " for every device." | 320 | " for every device." |
320 | "\n"); | 321 | "\n"); |
321 | MODULE_PARM_DESC(monochrome, | 322 | MODULE_PARM_DESC(monochrome, |
322 | "\n<0|1[,...]> Use image sensor as monochrome sensor:" | 323 | "\n<0|1[,...]> Use image sensor as monochrome sensor:" |
323 | "\n 0 = no, 1 = yes" | 324 | "\n 0 = no, 1 = yes" |
324 | "\nNot all the sensors support monochrome color." | 325 | "\nNot all the sensors support monochrome color." |
325 | "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) | 326 | "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) |
326 | " for every device." | 327 | " for every device." |
327 | "\n"); | 328 | "\n"); |
328 | MODULE_PARM_DESC(brightness, | 329 | MODULE_PARM_DESC(brightness, |
329 | "\n<n[,...]> Set picture brightness (0-65535)." | 330 | "\n<n[,...]> Set picture brightness (0-65535)." |
330 | "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) | 331 | "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) |
331 | " for every device." | 332 | " for every device." |
332 | "\nThis parameter has no effect if 'autobright' is enabled." | 333 | "\nThis parameter has no effect if 'autobright' is enabled." |
333 | "\n"); | 334 | "\n"); |
334 | MODULE_PARM_DESC(hue, | 335 | MODULE_PARM_DESC(hue, |
335 | "\n<n[,...]> Set picture hue (0-65535)." | 336 | "\n<n[,...]> Set picture hue (0-65535)." |
336 | "\nDefault value is "__MODULE_STRING(W9968CF_HUE) | 337 | "\nDefault value is "__MODULE_STRING(W9968CF_HUE) |
337 | " for every device." | 338 | " for every device." |
338 | "\n"); | 339 | "\n"); |
339 | MODULE_PARM_DESC(colour, | 340 | MODULE_PARM_DESC(colour, |
340 | "\n<n[,...]> Set picture saturation (0-65535)." | 341 | "\n<n[,...]> Set picture saturation (0-65535)." |
341 | "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) | 342 | "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) |
342 | " for every device." | 343 | " for every device." |
343 | "\n"); | 344 | "\n"); |
344 | MODULE_PARM_DESC(contrast, | 345 | MODULE_PARM_DESC(contrast, |
345 | "\n<n[,...]> Set picture contrast (0-65535)." | 346 | "\n<n[,...]> Set picture contrast (0-65535)." |
346 | "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) | 347 | "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) |
347 | " for every device." | 348 | " for every device." |
348 | "\n"); | 349 | "\n"); |
349 | MODULE_PARM_DESC(whiteness, | 350 | MODULE_PARM_DESC(whiteness, |
350 | "\n<n[,...]> Set picture whiteness (0-65535)." | 351 | "\n<n[,...]> Set picture whiteness (0-65535)." |
351 | "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) | 352 | "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) |
352 | " for every device." | 353 | " for every device." |
353 | "\n"); | 354 | "\n"); |
354 | #ifdef W9968CF_DEBUG | 355 | #ifdef W9968CF_DEBUG |
355 | MODULE_PARM_DESC(debug, | 356 | MODULE_PARM_DESC(debug, |
356 | "\n<n> Debugging information level, from 0 to 6:" | 357 | "\n<n> Debugging information level, from 0 to 6:" |
357 | "\n0 = none (use carefully)" | 358 | "\n0 = none (use carefully)" |
358 | "\n1 = critical errors" | 359 | "\n1 = critical errors" |
359 | "\n2 = significant informations" | 360 | "\n2 = significant informations" |
360 | "\n3 = configuration or general messages" | 361 | "\n3 = configuration or general messages" |
361 | "\n4 = warnings" | 362 | "\n4 = warnings" |
362 | "\n5 = called functions" | 363 | "\n5 = called functions" |
363 | "\n6 = function internals" | 364 | "\n6 = function internals" |
364 | "\nLevel 5 and 6 are useful for testing only, when only " | 365 | "\nLevel 5 and 6 are useful for testing only, when only " |
365 | "one device is used." | 366 | "one device is used." |
366 | "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." | 367 | "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." |
367 | "\n"); | 368 | "\n"); |
368 | MODULE_PARM_DESC(specific_debug, | 369 | MODULE_PARM_DESC(specific_debug, |
369 | "\n<0|1> Enable or disable specific debugging messages:" | 370 | "\n<0|1> Enable or disable specific debugging messages:" |
370 | "\n0 = print messages concerning every level" | 371 | "\n0 = print messages concerning every level" |
371 | " <= 'debug' level." | 372 | " <= 'debug' level." |
372 | "\n1 = print messages concerning the level" | 373 | "\n1 = print messages concerning the level" |
373 | " indicated by 'debug'." | 374 | " indicated by 'debug'." |
374 | "\nDefault value is " | 375 | "\nDefault value is " |
375 | __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." | 376 | __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." |
376 | "\n"); | 377 | "\n"); |
377 | #endif /* W9968CF_DEBUG */ | 378 | #endif /* W9968CF_DEBUG */ |
378 | 379 | ||
379 | 380 | ||
380 | 381 | ||
381 | /**************************************************************************** | 382 | /**************************************************************************** |
382 | * Some prototypes * | 383 | * Some prototypes * |
383 | ****************************************************************************/ | 384 | ****************************************************************************/ |
384 | 385 | ||
385 | /* Video4linux interface */ | 386 | /* Video4linux interface */ |
386 | static const struct v4l2_file_operations w9968cf_fops; | 387 | static const struct v4l2_file_operations w9968cf_fops; |
387 | static int w9968cf_open(struct file *); | 388 | static int w9968cf_open(struct file *); |
388 | static int w9968cf_release(struct file *); | 389 | static int w9968cf_release(struct file *); |
389 | static int w9968cf_mmap(struct file *, struct vm_area_struct *); | 390 | static int w9968cf_mmap(struct file *, struct vm_area_struct *); |
390 | static long w9968cf_ioctl(struct file *, unsigned, unsigned long); | 391 | static long w9968cf_ioctl(struct file *, unsigned, unsigned long); |
391 | static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *); | 392 | static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *); |
392 | static long w9968cf_v4l_ioctl(struct file *, unsigned int, | 393 | static long w9968cf_v4l_ioctl(struct file *, unsigned int, |
393 | void __user *); | 394 | void __user *); |
394 | 395 | ||
395 | /* USB-specific */ | 396 | /* USB-specific */ |
396 | static int w9968cf_start_transfer(struct w9968cf_device*); | 397 | static int w9968cf_start_transfer(struct w9968cf_device*); |
397 | static int w9968cf_stop_transfer(struct w9968cf_device*); | 398 | static int w9968cf_stop_transfer(struct w9968cf_device*); |
398 | static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); | 399 | static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); |
399 | static int w9968cf_read_reg(struct w9968cf_device*, u16 index); | 400 | static int w9968cf_read_reg(struct w9968cf_device*, u16 index); |
400 | static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); | 401 | static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); |
401 | static int w9968cf_write_sb(struct w9968cf_device*, u16 value); | 402 | static int w9968cf_write_sb(struct w9968cf_device*, u16 value); |
402 | static int w9968cf_read_sb(struct w9968cf_device*); | 403 | static int w9968cf_read_sb(struct w9968cf_device*); |
403 | static int w9968cf_upload_quantizationtables(struct w9968cf_device*); | 404 | static int w9968cf_upload_quantizationtables(struct w9968cf_device*); |
404 | static void w9968cf_urb_complete(struct urb *urb); | 405 | static void w9968cf_urb_complete(struct urb *urb); |
405 | 406 | ||
406 | /* Low-level I2C (SMBus) I/O */ | 407 | /* Low-level I2C (SMBus) I/O */ |
407 | static int w9968cf_smbus_start(struct w9968cf_device*); | 408 | static int w9968cf_smbus_start(struct w9968cf_device*); |
408 | static int w9968cf_smbus_stop(struct w9968cf_device*); | 409 | static int w9968cf_smbus_stop(struct w9968cf_device*); |
409 | static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); | 410 | static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); |
410 | static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); | 411 | static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); |
411 | static int w9968cf_smbus_write_ack(struct w9968cf_device*); | 412 | static int w9968cf_smbus_write_ack(struct w9968cf_device*); |
412 | static int w9968cf_smbus_read_ack(struct w9968cf_device*); | 413 | static int w9968cf_smbus_read_ack(struct w9968cf_device*); |
413 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); | 414 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); |
414 | static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | 415 | static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, |
415 | u16 address, u8* value); | 416 | u16 address, u8* value); |
416 | static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, | 417 | static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, |
417 | u8 subaddress, u8* value); | 418 | u8 subaddress, u8* value); |
418 | static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, | 419 | static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, |
419 | u16 address, u8 subaddress); | 420 | u16 address, u8 subaddress); |
420 | static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, | 421 | static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, |
421 | u16 address, u8 subaddress, | 422 | u16 address, u8 subaddress, |
422 | u8 value); | 423 | u8 value); |
423 | 424 | ||
424 | /* I2C interface to kernel */ | 425 | /* I2C interface to kernel */ |
425 | static int w9968cf_i2c_init(struct w9968cf_device*); | 426 | static int w9968cf_i2c_init(struct w9968cf_device*); |
426 | static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, | 427 | static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, |
427 | unsigned short flags, char read_write, | 428 | unsigned short flags, char read_write, |
428 | u8 command, int size, union i2c_smbus_data*); | 429 | u8 command, int size, union i2c_smbus_data*); |
429 | static u32 w9968cf_i2c_func(struct i2c_adapter*); | 430 | static u32 w9968cf_i2c_func(struct i2c_adapter*); |
430 | 431 | ||
431 | /* Memory management */ | 432 | /* Memory management */ |
432 | static void* rvmalloc(unsigned long size); | 433 | static void* rvmalloc(unsigned long size); |
433 | static void rvfree(void *mem, unsigned long size); | 434 | static void rvfree(void *mem, unsigned long size); |
434 | static void w9968cf_deallocate_memory(struct w9968cf_device*); | 435 | static void w9968cf_deallocate_memory(struct w9968cf_device*); |
435 | static int w9968cf_allocate_memory(struct w9968cf_device*); | 436 | static int w9968cf_allocate_memory(struct w9968cf_device*); |
436 | 437 | ||
437 | /* High-level image sensor control functions */ | 438 | /* High-level image sensor control functions */ |
438 | static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); | 439 | static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); |
439 | static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); | 440 | static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); |
440 | static int w9968cf_sensor_cmd(struct w9968cf_device*, | 441 | static int w9968cf_sensor_cmd(struct w9968cf_device*, |
441 | unsigned int cmd, void *arg); | 442 | unsigned int cmd, void *arg); |
442 | static int w9968cf_sensor_init(struct w9968cf_device*); | 443 | static int w9968cf_sensor_init(struct w9968cf_device*); |
443 | static int w9968cf_sensor_update_settings(struct w9968cf_device*); | 444 | static int w9968cf_sensor_update_settings(struct w9968cf_device*); |
444 | static int w9968cf_sensor_get_picture(struct w9968cf_device*); | 445 | static int w9968cf_sensor_get_picture(struct w9968cf_device*); |
445 | static int w9968cf_sensor_update_picture(struct w9968cf_device*, | 446 | static int w9968cf_sensor_update_picture(struct w9968cf_device*, |
446 | struct video_picture pict); | 447 | struct video_picture pict); |
447 | 448 | ||
448 | /* Other helper functions */ | 449 | /* Other helper functions */ |
449 | static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, | 450 | static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, |
450 | enum w9968cf_model_id, | 451 | enum w9968cf_model_id, |
451 | const unsigned short dev_nr); | 452 | const unsigned short dev_nr); |
452 | static void w9968cf_adjust_configuration(struct w9968cf_device*); | 453 | static void w9968cf_adjust_configuration(struct w9968cf_device*); |
453 | static int w9968cf_turn_on_led(struct w9968cf_device*); | 454 | static int w9968cf_turn_on_led(struct w9968cf_device*); |
454 | static int w9968cf_init_chip(struct w9968cf_device*); | 455 | static int w9968cf_init_chip(struct w9968cf_device*); |
455 | static inline u16 w9968cf_valid_palette(u16 palette); | 456 | static inline u16 w9968cf_valid_palette(u16 palette); |
456 | static inline u16 w9968cf_valid_depth(u16 palette); | 457 | static inline u16 w9968cf_valid_depth(u16 palette); |
457 | static inline u8 w9968cf_need_decompression(u16 palette); | 458 | static inline u8 w9968cf_need_decompression(u16 palette); |
458 | static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); | 459 | static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); |
459 | static int w9968cf_set_window(struct w9968cf_device*, struct video_window); | 460 | static int w9968cf_set_window(struct w9968cf_device*, struct video_window); |
460 | static int w9968cf_postprocess_frame(struct w9968cf_device*, | 461 | static int w9968cf_postprocess_frame(struct w9968cf_device*, |
461 | struct w9968cf_frame_t*); | 462 | struct w9968cf_frame_t*); |
462 | static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); | 463 | static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); |
463 | static void w9968cf_init_framelist(struct w9968cf_device*); | 464 | static void w9968cf_init_framelist(struct w9968cf_device*); |
464 | static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); | 465 | static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); |
465 | static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); | 466 | static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); |
466 | static void w9968cf_release_resources(struct w9968cf_device*); | 467 | static void w9968cf_release_resources(struct w9968cf_device*); |
467 | 468 | ||
468 | 469 | ||
469 | 470 | ||
470 | /**************************************************************************** | 471 | /**************************************************************************** |
471 | * Symbolic names * | 472 | * Symbolic names * |
472 | ****************************************************************************/ | 473 | ****************************************************************************/ |
473 | 474 | ||
474 | /* Used to represent a list of values and their respective symbolic names */ | 475 | /* Used to represent a list of values and their respective symbolic names */ |
475 | struct w9968cf_symbolic_list { | 476 | struct w9968cf_symbolic_list { |
476 | const int num; | 477 | const int num; |
477 | const char *name; | 478 | const char *name; |
478 | }; | 479 | }; |
479 | 480 | ||
480 | /*-------------------------------------------------------------------------- | 481 | /*-------------------------------------------------------------------------- |
481 | Returns the name of the matching element in the symbolic_list array. The | 482 | Returns the name of the matching element in the symbolic_list array. The |
482 | end of the list must be marked with an element that has a NULL name. | 483 | end of the list must be marked with an element that has a NULL name. |
483 | --------------------------------------------------------------------------*/ | 484 | --------------------------------------------------------------------------*/ |
484 | static inline const char * | 485 | static inline const char * |
485 | symbolic(struct w9968cf_symbolic_list list[], const int num) | 486 | symbolic(struct w9968cf_symbolic_list list[], const int num) |
486 | { | 487 | { |
487 | int i; | 488 | int i; |
488 | 489 | ||
489 | for (i = 0; list[i].name != NULL; i++) | 490 | for (i = 0; list[i].name != NULL; i++) |
490 | if (list[i].num == num) | 491 | if (list[i].num == num) |
491 | return (list[i].name); | 492 | return (list[i].name); |
492 | 493 | ||
493 | return "Unknown"; | 494 | return "Unknown"; |
494 | } | 495 | } |
495 | 496 | ||
496 | static struct w9968cf_symbolic_list camlist[] = { | 497 | static struct w9968cf_symbolic_list camlist[] = { |
497 | { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, | 498 | { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, |
498 | { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, | 499 | { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, |
499 | 500 | ||
500 | /* Other cameras (having the same descriptors as Generic W996[87]CF) */ | 501 | /* Other cameras (having the same descriptors as Generic W996[87]CF) */ |
501 | { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, | 502 | { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, |
502 | { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, | 503 | { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, |
503 | { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, | 504 | { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, |
504 | { W9968CF_MOD_LL, "Lebon LDC-035A" }, | 505 | { W9968CF_MOD_LL, "Lebon LDC-035A" }, |
505 | { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, | 506 | { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, |
506 | { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, | 507 | { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, |
507 | { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, | 508 | { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, |
508 | { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, | 509 | { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, |
509 | { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, | 510 | { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, |
510 | 511 | ||
511 | { -1, NULL } | 512 | { -1, NULL } |
512 | }; | 513 | }; |
513 | 514 | ||
514 | static struct w9968cf_symbolic_list senlist[] = { | 515 | static struct w9968cf_symbolic_list senlist[] = { |
515 | { CC_OV76BE, "OV76BE" }, | 516 | { CC_OV76BE, "OV76BE" }, |
516 | { CC_OV7610, "OV7610" }, | 517 | { CC_OV7610, "OV7610" }, |
517 | { CC_OV7620, "OV7620" }, | 518 | { CC_OV7620, "OV7620" }, |
518 | { CC_OV7620AE, "OV7620AE" }, | 519 | { CC_OV7620AE, "OV7620AE" }, |
519 | { CC_OV6620, "OV6620" }, | 520 | { CC_OV6620, "OV6620" }, |
520 | { CC_OV6630, "OV6630" }, | 521 | { CC_OV6630, "OV6630" }, |
521 | { CC_OV6630AE, "OV6630AE" }, | 522 | { CC_OV6630AE, "OV6630AE" }, |
522 | { CC_OV6630AF, "OV6630AF" }, | 523 | { CC_OV6630AF, "OV6630AF" }, |
523 | { -1, NULL } | 524 | { -1, NULL } |
524 | }; | 525 | }; |
525 | 526 | ||
526 | /* Video4Linux1 palettes */ | 527 | /* Video4Linux1 palettes */ |
527 | static struct w9968cf_symbolic_list v4l1_plist[] = { | 528 | static struct w9968cf_symbolic_list v4l1_plist[] = { |
528 | { VIDEO_PALETTE_GREY, "GREY" }, | 529 | { VIDEO_PALETTE_GREY, "GREY" }, |
529 | { VIDEO_PALETTE_HI240, "HI240" }, | 530 | { VIDEO_PALETTE_HI240, "HI240" }, |
530 | { VIDEO_PALETTE_RGB565, "RGB565" }, | 531 | { VIDEO_PALETTE_RGB565, "RGB565" }, |
531 | { VIDEO_PALETTE_RGB24, "RGB24" }, | 532 | { VIDEO_PALETTE_RGB24, "RGB24" }, |
532 | { VIDEO_PALETTE_RGB32, "RGB32" }, | 533 | { VIDEO_PALETTE_RGB32, "RGB32" }, |
533 | { VIDEO_PALETTE_RGB555, "RGB555" }, | 534 | { VIDEO_PALETTE_RGB555, "RGB555" }, |
534 | { VIDEO_PALETTE_YUV422, "YUV422" }, | 535 | { VIDEO_PALETTE_YUV422, "YUV422" }, |
535 | { VIDEO_PALETTE_YUYV, "YUYV" }, | 536 | { VIDEO_PALETTE_YUYV, "YUYV" }, |
536 | { VIDEO_PALETTE_UYVY, "UYVY" }, | 537 | { VIDEO_PALETTE_UYVY, "UYVY" }, |
537 | { VIDEO_PALETTE_YUV420, "YUV420" }, | 538 | { VIDEO_PALETTE_YUV420, "YUV420" }, |
538 | { VIDEO_PALETTE_YUV411, "YUV411" }, | 539 | { VIDEO_PALETTE_YUV411, "YUV411" }, |
539 | { VIDEO_PALETTE_RAW, "RAW" }, | 540 | { VIDEO_PALETTE_RAW, "RAW" }, |
540 | { VIDEO_PALETTE_YUV422P, "YUV422P" }, | 541 | { VIDEO_PALETTE_YUV422P, "YUV422P" }, |
541 | { VIDEO_PALETTE_YUV411P, "YUV411P" }, | 542 | { VIDEO_PALETTE_YUV411P, "YUV411P" }, |
542 | { VIDEO_PALETTE_YUV420P, "YUV420P" }, | 543 | { VIDEO_PALETTE_YUV420P, "YUV420P" }, |
543 | { VIDEO_PALETTE_YUV410P, "YUV410P" }, | 544 | { VIDEO_PALETTE_YUV410P, "YUV410P" }, |
544 | { -1, NULL } | 545 | { -1, NULL } |
545 | }; | 546 | }; |
546 | 547 | ||
547 | /* Decoder error codes: */ | 548 | /* Decoder error codes: */ |
548 | static struct w9968cf_symbolic_list decoder_errlist[] = { | 549 | static struct w9968cf_symbolic_list decoder_errlist[] = { |
549 | { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, | 550 | { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, |
550 | { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, | 551 | { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, |
551 | { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, | 552 | { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, |
552 | { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, | 553 | { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, |
553 | { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, | 554 | { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, |
554 | { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, | 555 | { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, |
555 | { -1, NULL } | 556 | { -1, NULL } |
556 | }; | 557 | }; |
557 | 558 | ||
558 | /* URB error codes: */ | 559 | /* URB error codes: */ |
559 | static struct w9968cf_symbolic_list urb_errlist[] = { | 560 | static struct w9968cf_symbolic_list urb_errlist[] = { |
560 | { -ENOMEM, "No memory for allocation of internal structures" }, | 561 | { -ENOMEM, "No memory for allocation of internal structures" }, |
561 | { -ENOSPC, "The host controller's bandwidth is already consumed" }, | 562 | { -ENOSPC, "The host controller's bandwidth is already consumed" }, |
562 | { -ENOENT, "URB was canceled by unlink_urb" }, | 563 | { -ENOENT, "URB was canceled by unlink_urb" }, |
563 | { -EXDEV, "ISO transfer only partially completed" }, | 564 | { -EXDEV, "ISO transfer only partially completed" }, |
564 | { -EAGAIN, "Too match scheduled for the future" }, | 565 | { -EAGAIN, "Too match scheduled for the future" }, |
565 | { -ENXIO, "URB already queued" }, | 566 | { -ENXIO, "URB already queued" }, |
566 | { -EFBIG, "Too much ISO frames requested" }, | 567 | { -EFBIG, "Too much ISO frames requested" }, |
567 | { -ENOSR, "Buffer error (overrun)" }, | 568 | { -ENOSR, "Buffer error (overrun)" }, |
568 | { -EPIPE, "Specified endpoint is stalled (device not responding)"}, | 569 | { -EPIPE, "Specified endpoint is stalled (device not responding)"}, |
569 | { -EOVERFLOW, "Babble (too much data)" }, | 570 | { -EOVERFLOW, "Babble (too much data)" }, |
570 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | 571 | { -EPROTO, "Bit-stuff error (bad cable?)" }, |
571 | { -EILSEQ, "CRC/Timeout" }, | 572 | { -EILSEQ, "CRC/Timeout" }, |
572 | { -ETIME, "Device does not respond to token" }, | 573 | { -ETIME, "Device does not respond to token" }, |
573 | { -ETIMEDOUT, "Device does not respond to command" }, | 574 | { -ETIMEDOUT, "Device does not respond to command" }, |
574 | { -1, NULL } | 575 | { -1, NULL } |
575 | }; | 576 | }; |
576 | 577 | ||
577 | /**************************************************************************** | 578 | /**************************************************************************** |
578 | * Memory management functions * | 579 | * Memory management functions * |
579 | ****************************************************************************/ | 580 | ****************************************************************************/ |
580 | static void* rvmalloc(unsigned long size) | 581 | static void* rvmalloc(unsigned long size) |
581 | { | 582 | { |
582 | void* mem; | 583 | void* mem; |
583 | unsigned long adr; | 584 | unsigned long adr; |
584 | 585 | ||
585 | size = PAGE_ALIGN(size); | 586 | size = PAGE_ALIGN(size); |
586 | mem = vmalloc_32(size); | 587 | mem = vmalloc_32(size); |
587 | if (!mem) | 588 | if (!mem) |
588 | return NULL; | 589 | return NULL; |
589 | 590 | ||
590 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | 591 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ |
591 | adr = (unsigned long) mem; | 592 | adr = (unsigned long) mem; |
592 | while (size > 0) { | 593 | while (size > 0) { |
593 | SetPageReserved(vmalloc_to_page((void *)adr)); | 594 | SetPageReserved(vmalloc_to_page((void *)adr)); |
594 | adr += PAGE_SIZE; | 595 | adr += PAGE_SIZE; |
595 | size -= PAGE_SIZE; | 596 | size -= PAGE_SIZE; |
596 | } | 597 | } |
597 | 598 | ||
598 | return mem; | 599 | return mem; |
599 | } | 600 | } |
600 | 601 | ||
601 | 602 | ||
602 | static void rvfree(void* mem, unsigned long size) | 603 | static void rvfree(void* mem, unsigned long size) |
603 | { | 604 | { |
604 | unsigned long adr; | 605 | unsigned long adr; |
605 | 606 | ||
606 | if (!mem) | 607 | if (!mem) |
607 | return; | 608 | return; |
608 | 609 | ||
609 | adr = (unsigned long) mem; | 610 | adr = (unsigned long) mem; |
610 | while ((long) size > 0) { | 611 | while ((long) size > 0) { |
611 | ClearPageReserved(vmalloc_to_page((void *)adr)); | 612 | ClearPageReserved(vmalloc_to_page((void *)adr)); |
612 | adr += PAGE_SIZE; | 613 | adr += PAGE_SIZE; |
613 | size -= PAGE_SIZE; | 614 | size -= PAGE_SIZE; |
614 | } | 615 | } |
615 | vfree(mem); | 616 | vfree(mem); |
616 | } | 617 | } |
617 | 618 | ||
618 | 619 | ||
619 | /*-------------------------------------------------------------------------- | 620 | /*-------------------------------------------------------------------------- |
620 | Deallocate previously allocated memory. | 621 | Deallocate previously allocated memory. |
621 | --------------------------------------------------------------------------*/ | 622 | --------------------------------------------------------------------------*/ |
622 | static void w9968cf_deallocate_memory(struct w9968cf_device* cam) | 623 | static void w9968cf_deallocate_memory(struct w9968cf_device* cam) |
623 | { | 624 | { |
624 | u8 i; | 625 | u8 i; |
625 | 626 | ||
626 | /* Free the isochronous transfer buffers */ | 627 | /* Free the isochronous transfer buffers */ |
627 | for (i = 0; i < W9968CF_URBS; i++) { | 628 | for (i = 0; i < W9968CF_URBS; i++) { |
628 | kfree(cam->transfer_buffer[i]); | 629 | kfree(cam->transfer_buffer[i]); |
629 | cam->transfer_buffer[i] = NULL; | 630 | cam->transfer_buffer[i] = NULL; |
630 | } | 631 | } |
631 | 632 | ||
632 | /* Free temporary frame buffer */ | 633 | /* Free temporary frame buffer */ |
633 | if (cam->frame_tmp.buffer) { | 634 | if (cam->frame_tmp.buffer) { |
634 | rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); | 635 | rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); |
635 | cam->frame_tmp.buffer = NULL; | 636 | cam->frame_tmp.buffer = NULL; |
636 | } | 637 | } |
637 | 638 | ||
638 | /* Free helper buffer */ | 639 | /* Free helper buffer */ |
639 | if (cam->frame_vpp.buffer) { | 640 | if (cam->frame_vpp.buffer) { |
640 | rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); | 641 | rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); |
641 | cam->frame_vpp.buffer = NULL; | 642 | cam->frame_vpp.buffer = NULL; |
642 | } | 643 | } |
643 | 644 | ||
644 | /* Free video frame buffers */ | 645 | /* Free video frame buffers */ |
645 | if (cam->frame[0].buffer) { | 646 | if (cam->frame[0].buffer) { |
646 | rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); | 647 | rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); |
647 | cam->frame[0].buffer = NULL; | 648 | cam->frame[0].buffer = NULL; |
648 | } | 649 | } |
649 | 650 | ||
650 | cam->nbuffers = 0; | 651 | cam->nbuffers = 0; |
651 | 652 | ||
652 | DBG(5, "Memory successfully deallocated") | 653 | DBG(5, "Memory successfully deallocated") |
653 | } | 654 | } |
654 | 655 | ||
655 | 656 | ||
656 | /*-------------------------------------------------------------------------- | 657 | /*-------------------------------------------------------------------------- |
657 | Allocate memory buffers for USB transfers and video frames. | 658 | Allocate memory buffers for USB transfers and video frames. |
658 | This function is called by open() only. | 659 | This function is called by open() only. |
659 | Return 0 on success, a negative number otherwise. | 660 | Return 0 on success, a negative number otherwise. |
660 | --------------------------------------------------------------------------*/ | 661 | --------------------------------------------------------------------------*/ |
661 | static int w9968cf_allocate_memory(struct w9968cf_device* cam) | 662 | static int w9968cf_allocate_memory(struct w9968cf_device* cam) |
662 | { | 663 | { |
663 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | 664 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; |
664 | void* buff = NULL; | 665 | void* buff = NULL; |
665 | unsigned long hw_bufsize, vpp_bufsize; | 666 | unsigned long hw_bufsize, vpp_bufsize; |
666 | u8 i, bpp; | 667 | u8 i, bpp; |
667 | 668 | ||
668 | /* NOTE: Deallocation is done elsewhere in case of error */ | 669 | /* NOTE: Deallocation is done elsewhere in case of error */ |
669 | 670 | ||
670 | /* Calculate the max amount of raw data per frame from the device */ | 671 | /* Calculate the max amount of raw data per frame from the device */ |
671 | hw_bufsize = cam->maxwidth*cam->maxheight*2; | 672 | hw_bufsize = cam->maxwidth*cam->maxheight*2; |
672 | 673 | ||
673 | /* Calculate the max buf. size needed for post-processing routines */ | 674 | /* Calculate the max buf. size needed for post-processing routines */ |
674 | bpp = (w9968cf_vpp) ? 4 : 2; | 675 | bpp = (w9968cf_vpp) ? 4 : 2; |
675 | if (cam->upscaling) | 676 | if (cam->upscaling) |
676 | vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, | 677 | vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, |
677 | cam->maxwidth*cam->maxheight*bpp); | 678 | cam->maxwidth*cam->maxheight*bpp); |
678 | else | 679 | else |
679 | vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; | 680 | vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; |
680 | 681 | ||
681 | /* Allocate memory for the isochronous transfer buffers */ | 682 | /* Allocate memory for the isochronous transfer buffers */ |
682 | for (i = 0; i < W9968CF_URBS; i++) { | 683 | for (i = 0; i < W9968CF_URBS; i++) { |
683 | if (!(cam->transfer_buffer[i] = | 684 | if (!(cam->transfer_buffer[i] = |
684 | kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { | 685 | kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { |
685 | DBG(1, "Couldn't allocate memory for the isochronous " | 686 | DBG(1, "Couldn't allocate memory for the isochronous " |
686 | "transfer buffers (%u bytes)", | 687 | "transfer buffers (%u bytes)", |
687 | p_size * W9968CF_ISO_PACKETS) | 688 | p_size * W9968CF_ISO_PACKETS) |
688 | return -ENOMEM; | 689 | return -ENOMEM; |
689 | } | 690 | } |
690 | } | 691 | } |
691 | 692 | ||
692 | /* Allocate memory for the temporary frame buffer */ | 693 | /* Allocate memory for the temporary frame buffer */ |
693 | if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { | 694 | if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { |
694 | DBG(1, "Couldn't allocate memory for the temporary " | 695 | DBG(1, "Couldn't allocate memory for the temporary " |
695 | "video frame buffer (%lu bytes)", hw_bufsize) | 696 | "video frame buffer (%lu bytes)", hw_bufsize) |
696 | return -ENOMEM; | 697 | return -ENOMEM; |
697 | } | 698 | } |
698 | cam->frame_tmp.size = hw_bufsize; | 699 | cam->frame_tmp.size = hw_bufsize; |
699 | cam->frame_tmp.number = -1; | 700 | cam->frame_tmp.number = -1; |
700 | 701 | ||
701 | /* Allocate memory for the helper buffer */ | 702 | /* Allocate memory for the helper buffer */ |
702 | if (w9968cf_vpp) { | 703 | if (w9968cf_vpp) { |
703 | if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { | 704 | if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { |
704 | DBG(1, "Couldn't allocate memory for the helper buffer" | 705 | DBG(1, "Couldn't allocate memory for the helper buffer" |
705 | " (%lu bytes)", vpp_bufsize) | 706 | " (%lu bytes)", vpp_bufsize) |
706 | return -ENOMEM; | 707 | return -ENOMEM; |
707 | } | 708 | } |
708 | cam->frame_vpp.size = vpp_bufsize; | 709 | cam->frame_vpp.size = vpp_bufsize; |
709 | } else | 710 | } else |
710 | cam->frame_vpp.buffer = NULL; | 711 | cam->frame_vpp.buffer = NULL; |
711 | 712 | ||
712 | /* Allocate memory for video frame buffers */ | 713 | /* Allocate memory for video frame buffers */ |
713 | cam->nbuffers = cam->max_buffers; | 714 | cam->nbuffers = cam->max_buffers; |
714 | while (cam->nbuffers >= 2) { | 715 | while (cam->nbuffers >= 2) { |
715 | if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) | 716 | if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) |
716 | break; | 717 | break; |
717 | else | 718 | else |
718 | cam->nbuffers--; | 719 | cam->nbuffers--; |
719 | } | 720 | } |
720 | 721 | ||
721 | if (!buff) { | 722 | if (!buff) { |
722 | DBG(1, "Couldn't allocate memory for the video frame buffers") | 723 | DBG(1, "Couldn't allocate memory for the video frame buffers") |
723 | cam->nbuffers = 0; | 724 | cam->nbuffers = 0; |
724 | return -ENOMEM; | 725 | return -ENOMEM; |
725 | } | 726 | } |
726 | 727 | ||
727 | if (cam->nbuffers != cam->max_buffers) | 728 | if (cam->nbuffers != cam->max_buffers) |
728 | DBG(2, "Couldn't allocate memory for %u video frame buffers. " | 729 | DBG(2, "Couldn't allocate memory for %u video frame buffers. " |
729 | "Only memory for %u buffers has been allocated", | 730 | "Only memory for %u buffers has been allocated", |
730 | cam->max_buffers, cam->nbuffers) | 731 | cam->max_buffers, cam->nbuffers) |
731 | 732 | ||
732 | for (i = 0; i < cam->nbuffers; i++) { | 733 | for (i = 0; i < cam->nbuffers; i++) { |
733 | cam->frame[i].buffer = buff + i*vpp_bufsize; | 734 | cam->frame[i].buffer = buff + i*vpp_bufsize; |
734 | cam->frame[i].size = vpp_bufsize; | 735 | cam->frame[i].size = vpp_bufsize; |
735 | cam->frame[i].number = i; | 736 | cam->frame[i].number = i; |
736 | /* Circular list */ | 737 | /* Circular list */ |
737 | if (i != cam->nbuffers-1) | 738 | if (i != cam->nbuffers-1) |
738 | cam->frame[i].next = &cam->frame[i+1]; | 739 | cam->frame[i].next = &cam->frame[i+1]; |
739 | else | 740 | else |
740 | cam->frame[i].next = &cam->frame[0]; | 741 | cam->frame[i].next = &cam->frame[0]; |
741 | cam->frame[i].status = F_UNUSED; | 742 | cam->frame[i].status = F_UNUSED; |
742 | } | 743 | } |
743 | 744 | ||
744 | DBG(5, "Memory successfully allocated") | 745 | DBG(5, "Memory successfully allocated") |
745 | return 0; | 746 | return 0; |
746 | } | 747 | } |
747 | 748 | ||
748 | 749 | ||
749 | 750 | ||
750 | /**************************************************************************** | 751 | /**************************************************************************** |
751 | * USB-specific functions * | 752 | * USB-specific functions * |
752 | ****************************************************************************/ | 753 | ****************************************************************************/ |
753 | 754 | ||
754 | /*-------------------------------------------------------------------------- | 755 | /*-------------------------------------------------------------------------- |
755 | This is an handler function which is called after the URBs are completed. | 756 | This is an handler function which is called after the URBs are completed. |
756 | It collects multiple data packets coming from the camera by putting them | 757 | It collects multiple data packets coming from the camera by putting them |
757 | into frame buffers: one or more zero data length data packets are used to | 758 | into frame buffers: one or more zero data length data packets are used to |
758 | mark the end of a video frame; the first non-zero data packet is the start | 759 | mark the end of a video frame; the first non-zero data packet is the start |
759 | of the next video frame; if an error is encountered in a packet, the entire | 760 | of the next video frame; if an error is encountered in a packet, the entire |
760 | video frame is discarded and grabbed again. | 761 | video frame is discarded and grabbed again. |
761 | If there are no requested frames in the FIFO list, packets are collected into | 762 | If there are no requested frames in the FIFO list, packets are collected into |
762 | a temporary buffer. | 763 | a temporary buffer. |
763 | --------------------------------------------------------------------------*/ | 764 | --------------------------------------------------------------------------*/ |
764 | static void w9968cf_urb_complete(struct urb *urb) | 765 | static void w9968cf_urb_complete(struct urb *urb) |
765 | { | 766 | { |
766 | struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; | 767 | struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; |
767 | struct w9968cf_frame_t** f; | 768 | struct w9968cf_frame_t** f; |
768 | unsigned int len, status; | 769 | unsigned int len, status; |
769 | void* pos; | 770 | void* pos; |
770 | u8 i; | 771 | u8 i; |
771 | int err = 0; | 772 | int err = 0; |
772 | 773 | ||
773 | if ((!cam->streaming) || cam->disconnected) { | 774 | if ((!cam->streaming) || cam->disconnected) { |
774 | DBG(4, "Got interrupt, but not streaming") | 775 | DBG(4, "Got interrupt, but not streaming") |
775 | return; | 776 | return; |
776 | } | 777 | } |
777 | 778 | ||
778 | /* "(*f)" will be used instead of "cam->frame_current" */ | 779 | /* "(*f)" will be used instead of "cam->frame_current" */ |
779 | f = &cam->frame_current; | 780 | f = &cam->frame_current; |
780 | 781 | ||
781 | /* If a frame has been requested and we are grabbing into | 782 | /* If a frame has been requested and we are grabbing into |
782 | the temporary frame, we'll switch to that requested frame */ | 783 | the temporary frame, we'll switch to that requested frame */ |
783 | if ((*f) == &cam->frame_tmp && *cam->requested_frame) { | 784 | if ((*f) == &cam->frame_tmp && *cam->requested_frame) { |
784 | if (cam->frame_tmp.status == F_GRABBING) { | 785 | if (cam->frame_tmp.status == F_GRABBING) { |
785 | w9968cf_pop_frame(cam, &cam->frame_current); | 786 | w9968cf_pop_frame(cam, &cam->frame_current); |
786 | (*f)->status = F_GRABBING; | 787 | (*f)->status = F_GRABBING; |
787 | (*f)->length = cam->frame_tmp.length; | 788 | (*f)->length = cam->frame_tmp.length; |
788 | memcpy((*f)->buffer, cam->frame_tmp.buffer, | 789 | memcpy((*f)->buffer, cam->frame_tmp.buffer, |
789 | (*f)->length); | 790 | (*f)->length); |
790 | DBG(6, "Switched from temp. frame to frame #%d", | 791 | DBG(6, "Switched from temp. frame to frame #%d", |
791 | (*f)->number) | 792 | (*f)->number) |
792 | } | 793 | } |
793 | } | 794 | } |
794 | 795 | ||
795 | for (i = 0; i < urb->number_of_packets; i++) { | 796 | for (i = 0; i < urb->number_of_packets; i++) { |
796 | len = urb->iso_frame_desc[i].actual_length; | 797 | len = urb->iso_frame_desc[i].actual_length; |
797 | status = urb->iso_frame_desc[i].status; | 798 | status = urb->iso_frame_desc[i].status; |
798 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | 799 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; |
799 | 800 | ||
800 | if (status && len != 0) { | 801 | if (status && len != 0) { |
801 | DBG(4, "URB failed, error in data packet " | 802 | DBG(4, "URB failed, error in data packet " |
802 | "(error #%u, %s)", | 803 | "(error #%u, %s)", |
803 | status, symbolic(urb_errlist, status)) | 804 | status, symbolic(urb_errlist, status)) |
804 | (*f)->status = F_ERROR; | 805 | (*f)->status = F_ERROR; |
805 | continue; | 806 | continue; |
806 | } | 807 | } |
807 | 808 | ||
808 | if (len) { /* start of frame */ | 809 | if (len) { /* start of frame */ |
809 | 810 | ||
810 | if ((*f)->status == F_UNUSED) { | 811 | if ((*f)->status == F_UNUSED) { |
811 | (*f)->status = F_GRABBING; | 812 | (*f)->status = F_GRABBING; |
812 | (*f)->length = 0; | 813 | (*f)->length = 0; |
813 | } | 814 | } |
814 | 815 | ||
815 | /* Buffer overflows shouldn't happen, however...*/ | 816 | /* Buffer overflows shouldn't happen, however...*/ |
816 | if ((*f)->length + len > (*f)->size) { | 817 | if ((*f)->length + len > (*f)->size) { |
817 | DBG(4, "Buffer overflow: bad data packets") | 818 | DBG(4, "Buffer overflow: bad data packets") |
818 | (*f)->status = F_ERROR; | 819 | (*f)->status = F_ERROR; |
819 | } | 820 | } |
820 | 821 | ||
821 | if ((*f)->status == F_GRABBING) { | 822 | if ((*f)->status == F_GRABBING) { |
822 | memcpy((*f)->buffer + (*f)->length, pos, len); | 823 | memcpy((*f)->buffer + (*f)->length, pos, len); |
823 | (*f)->length += len; | 824 | (*f)->length += len; |
824 | } | 825 | } |
825 | 826 | ||
826 | } else if ((*f)->status == F_GRABBING) { /* end of frame */ | 827 | } else if ((*f)->status == F_GRABBING) { /* end of frame */ |
827 | 828 | ||
828 | DBG(6, "Frame #%d successfully grabbed", (*f)->number) | 829 | DBG(6, "Frame #%d successfully grabbed", (*f)->number) |
829 | 830 | ||
830 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | 831 | if (cam->vpp_flag & VPP_DECOMPRESSION) { |
831 | err = w9968cf_vpp->check_headers((*f)->buffer, | 832 | err = w9968cf_vpp->check_headers((*f)->buffer, |
832 | (*f)->length); | 833 | (*f)->length); |
833 | if (err) { | 834 | if (err) { |
834 | DBG(4, "Skip corrupted frame: %s", | 835 | DBG(4, "Skip corrupted frame: %s", |
835 | symbolic(decoder_errlist, err)) | 836 | symbolic(decoder_errlist, err)) |
836 | (*f)->status = F_UNUSED; | 837 | (*f)->status = F_UNUSED; |
837 | continue; /* grab this frame again */ | 838 | continue; /* grab this frame again */ |
838 | } | 839 | } |
839 | } | 840 | } |
840 | 841 | ||
841 | (*f)->status = F_READY; | 842 | (*f)->status = F_READY; |
842 | (*f)->queued = 0; | 843 | (*f)->queued = 0; |
843 | 844 | ||
844 | /* Take a pointer to the new frame from the FIFO list. | 845 | /* Take a pointer to the new frame from the FIFO list. |
845 | If the list is empty,we'll use the temporary frame*/ | 846 | If the list is empty,we'll use the temporary frame*/ |
846 | if (*cam->requested_frame) | 847 | if (*cam->requested_frame) |
847 | w9968cf_pop_frame(cam, &cam->frame_current); | 848 | w9968cf_pop_frame(cam, &cam->frame_current); |
848 | else { | 849 | else { |
849 | cam->frame_current = &cam->frame_tmp; | 850 | cam->frame_current = &cam->frame_tmp; |
850 | (*f)->status = F_UNUSED; | 851 | (*f)->status = F_UNUSED; |
851 | } | 852 | } |
852 | 853 | ||
853 | } else if ((*f)->status == F_ERROR) | 854 | } else if ((*f)->status == F_ERROR) |
854 | (*f)->status = F_UNUSED; /* grab it again */ | 855 | (*f)->status = F_UNUSED; /* grab it again */ |
855 | 856 | ||
856 | PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", | 857 | PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", |
857 | (unsigned long)(*f)->length, i, len, (*f)->status) | 858 | (unsigned long)(*f)->length, i, len, (*f)->status) |
858 | 859 | ||
859 | } /* end for */ | 860 | } /* end for */ |
860 | 861 | ||
861 | /* Resubmit this URB */ | 862 | /* Resubmit this URB */ |
862 | urb->dev = cam->usbdev; | 863 | urb->dev = cam->usbdev; |
863 | urb->status = 0; | 864 | urb->status = 0; |
864 | spin_lock(&cam->urb_lock); | 865 | spin_lock(&cam->urb_lock); |
865 | if (cam->streaming) | 866 | if (cam->streaming) |
866 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { | 867 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { |
867 | cam->misconfigured = 1; | 868 | cam->misconfigured = 1; |
868 | DBG(1, "Couldn't resubmit the URB: error %d, %s", | 869 | DBG(1, "Couldn't resubmit the URB: error %d, %s", |
869 | err, symbolic(urb_errlist, err)) | 870 | err, symbolic(urb_errlist, err)) |
870 | } | 871 | } |
871 | spin_unlock(&cam->urb_lock); | 872 | spin_unlock(&cam->urb_lock); |
872 | 873 | ||
873 | /* Wake up the user process */ | 874 | /* Wake up the user process */ |
874 | wake_up_interruptible(&cam->wait_queue); | 875 | wake_up_interruptible(&cam->wait_queue); |
875 | } | 876 | } |
876 | 877 | ||
877 | 878 | ||
878 | /*--------------------------------------------------------------------------- | 879 | /*--------------------------------------------------------------------------- |
879 | Setup the URB structures for the isochronous transfer. | 880 | Setup the URB structures for the isochronous transfer. |
880 | Submit the URBs so that the data transfer begins. | 881 | Submit the URBs so that the data transfer begins. |
881 | Return 0 on success, a negative number otherwise. | 882 | Return 0 on success, a negative number otherwise. |
882 | ---------------------------------------------------------------------------*/ | 883 | ---------------------------------------------------------------------------*/ |
883 | static int w9968cf_start_transfer(struct w9968cf_device* cam) | 884 | static int w9968cf_start_transfer(struct w9968cf_device* cam) |
884 | { | 885 | { |
885 | struct usb_device *udev = cam->usbdev; | 886 | struct usb_device *udev = cam->usbdev; |
886 | struct urb* urb; | 887 | struct urb* urb; |
887 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | 888 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; |
888 | u16 w, h, d; | 889 | u16 w, h, d; |
889 | int vidcapt; | 890 | int vidcapt; |
890 | u32 t_size; | 891 | u32 t_size; |
891 | int err = 0; | 892 | int err = 0; |
892 | s8 i, j; | 893 | s8 i, j; |
893 | 894 | ||
894 | for (i = 0; i < W9968CF_URBS; i++) { | 895 | for (i = 0; i < W9968CF_URBS; i++) { |
895 | urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); | 896 | urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); |
896 | if (!urb) { | 897 | if (!urb) { |
897 | for (j = 0; j < i; j++) | 898 | for (j = 0; j < i; j++) |
898 | usb_free_urb(cam->urb[j]); | 899 | usb_free_urb(cam->urb[j]); |
899 | DBG(1, "Couldn't allocate the URB structures") | 900 | DBG(1, "Couldn't allocate the URB structures") |
900 | return -ENOMEM; | 901 | return -ENOMEM; |
901 | } | 902 | } |
902 | 903 | ||
903 | cam->urb[i] = urb; | 904 | cam->urb[i] = urb; |
904 | urb->dev = udev; | 905 | urb->dev = udev; |
905 | urb->context = (void*)cam; | 906 | urb->context = (void*)cam; |
906 | urb->pipe = usb_rcvisocpipe(udev, 1); | 907 | urb->pipe = usb_rcvisocpipe(udev, 1); |
907 | urb->transfer_flags = URB_ISO_ASAP; | 908 | urb->transfer_flags = URB_ISO_ASAP; |
908 | urb->number_of_packets = W9968CF_ISO_PACKETS; | 909 | urb->number_of_packets = W9968CF_ISO_PACKETS; |
909 | urb->complete = w9968cf_urb_complete; | 910 | urb->complete = w9968cf_urb_complete; |
910 | urb->transfer_buffer = cam->transfer_buffer[i]; | 911 | urb->transfer_buffer = cam->transfer_buffer[i]; |
911 | urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; | 912 | urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; |
912 | urb->interval = 1; | 913 | urb->interval = 1; |
913 | for (j = 0; j < W9968CF_ISO_PACKETS; j++) { | 914 | for (j = 0; j < W9968CF_ISO_PACKETS; j++) { |
914 | urb->iso_frame_desc[j].offset = p_size*j; | 915 | urb->iso_frame_desc[j].offset = p_size*j; |
915 | urb->iso_frame_desc[j].length = p_size; | 916 | urb->iso_frame_desc[j].length = p_size; |
916 | } | 917 | } |
917 | } | 918 | } |
918 | 919 | ||
919 | /* Transfer size per frame, in WORD ! */ | 920 | /* Transfer size per frame, in WORD ! */ |
920 | d = cam->hw_depth; | 921 | d = cam->hw_depth; |
921 | w = cam->hw_width; | 922 | w = cam->hw_width; |
922 | h = cam->hw_height; | 923 | h = cam->hw_height; |
923 | 924 | ||
924 | t_size = (w*h*d)/16; | 925 | t_size = (w*h*d)/16; |
925 | 926 | ||
926 | err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | 927 | err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ |
927 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | 928 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ |
928 | 929 | ||
929 | /* Transfer size */ | 930 | /* Transfer size */ |
930 | err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ | 931 | err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ |
931 | err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ | 932 | err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ |
932 | 933 | ||
933 | if (cam->vpp_flag & VPP_DECOMPRESSION) | 934 | if (cam->vpp_flag & VPP_DECOMPRESSION) |
934 | err += w9968cf_upload_quantizationtables(cam); | 935 | err += w9968cf_upload_quantizationtables(cam); |
935 | 936 | ||
936 | vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ | 937 | vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ |
937 | err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ | 938 | err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ |
938 | 939 | ||
939 | err += usb_set_interface(udev, 0, cam->altsetting); | 940 | err += usb_set_interface(udev, 0, cam->altsetting); |
940 | err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ | 941 | err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ |
941 | 942 | ||
942 | if (err || (vidcapt < 0)) { | 943 | if (err || (vidcapt < 0)) { |
943 | for (i = 0; i < W9968CF_URBS; i++) | 944 | for (i = 0; i < W9968CF_URBS; i++) |
944 | usb_free_urb(cam->urb[i]); | 945 | usb_free_urb(cam->urb[i]); |
945 | DBG(1, "Couldn't tell the camera to start the data transfer") | 946 | DBG(1, "Couldn't tell the camera to start the data transfer") |
946 | return err; | 947 | return err; |
947 | } | 948 | } |
948 | 949 | ||
949 | w9968cf_init_framelist(cam); | 950 | w9968cf_init_framelist(cam); |
950 | 951 | ||
951 | /* Begin to grab into the temporary buffer */ | 952 | /* Begin to grab into the temporary buffer */ |
952 | cam->frame_tmp.status = F_UNUSED; | 953 | cam->frame_tmp.status = F_UNUSED; |
953 | cam->frame_tmp.queued = 0; | 954 | cam->frame_tmp.queued = 0; |
954 | cam->frame_current = &cam->frame_tmp; | 955 | cam->frame_current = &cam->frame_tmp; |
955 | 956 | ||
956 | if (!(cam->vpp_flag & VPP_DECOMPRESSION)) | 957 | if (!(cam->vpp_flag & VPP_DECOMPRESSION)) |
957 | DBG(5, "Isochronous transfer size: %lu bytes/frame", | 958 | DBG(5, "Isochronous transfer size: %lu bytes/frame", |
958 | (unsigned long)t_size*2) | 959 | (unsigned long)t_size*2) |
959 | 960 | ||
960 | DBG(5, "Starting the isochronous transfer...") | 961 | DBG(5, "Starting the isochronous transfer...") |
961 | 962 | ||
962 | cam->streaming = 1; | 963 | cam->streaming = 1; |
963 | 964 | ||
964 | /* Submit the URBs */ | 965 | /* Submit the URBs */ |
965 | for (i = 0; i < W9968CF_URBS; i++) { | 966 | for (i = 0; i < W9968CF_URBS; i++) { |
966 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | 967 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); |
967 | if (err) { | 968 | if (err) { |
968 | cam->streaming = 0; | 969 | cam->streaming = 0; |
969 | for (j = i-1; j >= 0; j--) { | 970 | for (j = i-1; j >= 0; j--) { |
970 | usb_kill_urb(cam->urb[j]); | 971 | usb_kill_urb(cam->urb[j]); |
971 | usb_free_urb(cam->urb[j]); | 972 | usb_free_urb(cam->urb[j]); |
972 | } | 973 | } |
973 | DBG(1, "Couldn't send a transfer request to the " | 974 | DBG(1, "Couldn't send a transfer request to the " |
974 | "USB core (error #%d, %s)", err, | 975 | "USB core (error #%d, %s)", err, |
975 | symbolic(urb_errlist, err)) | 976 | symbolic(urb_errlist, err)) |
976 | return err; | 977 | return err; |
977 | } | 978 | } |
978 | } | 979 | } |
979 | 980 | ||
980 | return 0; | 981 | return 0; |
981 | } | 982 | } |
982 | 983 | ||
983 | 984 | ||
984 | /*-------------------------------------------------------------------------- | 985 | /*-------------------------------------------------------------------------- |
985 | Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). | 986 | Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). |
986 | Return 0 on success, a negative number otherwise. | 987 | Return 0 on success, a negative number otherwise. |
987 | --------------------------------------------------------------------------*/ | 988 | --------------------------------------------------------------------------*/ |
988 | static int w9968cf_stop_transfer(struct w9968cf_device* cam) | 989 | static int w9968cf_stop_transfer(struct w9968cf_device* cam) |
989 | { | 990 | { |
990 | struct usb_device *udev = cam->usbdev; | 991 | struct usb_device *udev = cam->usbdev; |
991 | unsigned long lock_flags; | 992 | unsigned long lock_flags; |
992 | int err = 0; | 993 | int err = 0; |
993 | s8 i; | 994 | s8 i; |
994 | 995 | ||
995 | if (!cam->streaming) | 996 | if (!cam->streaming) |
996 | return 0; | 997 | return 0; |
997 | 998 | ||
998 | /* This avoids race conditions with usb_submit_urb() | 999 | /* This avoids race conditions with usb_submit_urb() |
999 | in the URB completition handler */ | 1000 | in the URB completition handler */ |
1000 | spin_lock_irqsave(&cam->urb_lock, lock_flags); | 1001 | spin_lock_irqsave(&cam->urb_lock, lock_flags); |
1001 | cam->streaming = 0; | 1002 | cam->streaming = 0; |
1002 | spin_unlock_irqrestore(&cam->urb_lock, lock_flags); | 1003 | spin_unlock_irqrestore(&cam->urb_lock, lock_flags); |
1003 | 1004 | ||
1004 | for (i = W9968CF_URBS-1; i >= 0; i--) | 1005 | for (i = W9968CF_URBS-1; i >= 0; i--) |
1005 | if (cam->urb[i]) { | 1006 | if (cam->urb[i]) { |
1006 | usb_kill_urb(cam->urb[i]); | 1007 | usb_kill_urb(cam->urb[i]); |
1007 | usb_free_urb(cam->urb[i]); | 1008 | usb_free_urb(cam->urb[i]); |
1008 | cam->urb[i] = NULL; | 1009 | cam->urb[i] = NULL; |
1009 | } | 1010 | } |
1010 | 1011 | ||
1011 | if (cam->disconnected) | 1012 | if (cam->disconnected) |
1012 | goto exit; | 1013 | goto exit; |
1013 | 1014 | ||
1014 | err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ | 1015 | err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ |
1015 | err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | 1016 | err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ |
1016 | err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ | 1017 | err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ |
1017 | err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ | 1018 | err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ |
1018 | 1019 | ||
1019 | if (err) { | 1020 | if (err) { |
1020 | DBG(2, "Failed to tell the camera to stop the isochronous " | 1021 | DBG(2, "Failed to tell the camera to stop the isochronous " |
1021 | "transfer. However this is not a critical error.") | 1022 | "transfer. However this is not a critical error.") |
1022 | return -EIO; | 1023 | return -EIO; |
1023 | } | 1024 | } |
1024 | 1025 | ||
1025 | exit: | 1026 | exit: |
1026 | DBG(5, "Isochronous transfer stopped") | 1027 | DBG(5, "Isochronous transfer stopped") |
1027 | return 0; | 1028 | return 0; |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | 1031 | ||
1031 | /*-------------------------------------------------------------------------- | 1032 | /*-------------------------------------------------------------------------- |
1032 | Write a W9968CF register. | 1033 | Write a W9968CF register. |
1033 | Return 0 on success, -1 otherwise. | 1034 | Return 0 on success, -1 otherwise. |
1034 | --------------------------------------------------------------------------*/ | 1035 | --------------------------------------------------------------------------*/ |
1035 | static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) | 1036 | static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) |
1036 | { | 1037 | { |
1037 | struct usb_device* udev = cam->usbdev; | 1038 | struct usb_device* udev = cam->usbdev; |
1038 | int res; | 1039 | int res; |
1039 | 1040 | ||
1040 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | 1041 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, |
1041 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | 1042 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
1042 | value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); | 1043 | value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); |
1043 | 1044 | ||
1044 | if (res < 0) | 1045 | if (res < 0) |
1045 | DBG(4, "Failed to write a register " | 1046 | DBG(4, "Failed to write a register " |
1046 | "(value 0x%04X, index 0x%02X, error #%d, %s)", | 1047 | "(value 0x%04X, index 0x%02X, error #%d, %s)", |
1047 | value, index, res, symbolic(urb_errlist, res)) | 1048 | value, index, res, symbolic(urb_errlist, res)) |
1048 | 1049 | ||
1049 | return (res >= 0) ? 0 : -1; | 1050 | return (res >= 0) ? 0 : -1; |
1050 | } | 1051 | } |
1051 | 1052 | ||
1052 | 1053 | ||
1053 | /*-------------------------------------------------------------------------- | 1054 | /*-------------------------------------------------------------------------- |
1054 | Read a W9968CF register. | 1055 | Read a W9968CF register. |
1055 | Return the register value on success, -1 otherwise. | 1056 | Return the register value on success, -1 otherwise. |
1056 | --------------------------------------------------------------------------*/ | 1057 | --------------------------------------------------------------------------*/ |
1057 | static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) | 1058 | static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) |
1058 | { | 1059 | { |
1059 | struct usb_device* udev = cam->usbdev; | 1060 | struct usb_device* udev = cam->usbdev; |
1060 | u16* buff = cam->control_buffer; | 1061 | u16* buff = cam->control_buffer; |
1061 | int res; | 1062 | int res; |
1062 | 1063 | ||
1063 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, | 1064 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, |
1064 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 1065 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
1065 | 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); | 1066 | 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); |
1066 | 1067 | ||
1067 | if (res < 0) | 1068 | if (res < 0) |
1068 | DBG(4, "Failed to read a register " | 1069 | DBG(4, "Failed to read a register " |
1069 | "(index 0x%02X, error #%d, %s)", | 1070 | "(index 0x%02X, error #%d, %s)", |
1070 | index, res, symbolic(urb_errlist, res)) | 1071 | index, res, symbolic(urb_errlist, res)) |
1071 | 1072 | ||
1072 | return (res >= 0) ? (int)(*buff) : -1; | 1073 | return (res >= 0) ? (int)(*buff) : -1; |
1073 | } | 1074 | } |
1074 | 1075 | ||
1075 | 1076 | ||
1076 | /*-------------------------------------------------------------------------- | 1077 | /*-------------------------------------------------------------------------- |
1077 | Write 64-bit data to the fast serial bus registers. | 1078 | Write 64-bit data to the fast serial bus registers. |
1078 | Return 0 on success, -1 otherwise. | 1079 | Return 0 on success, -1 otherwise. |
1079 | --------------------------------------------------------------------------*/ | 1080 | --------------------------------------------------------------------------*/ |
1080 | static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) | 1081 | static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) |
1081 | { | 1082 | { |
1082 | struct usb_device* udev = cam->usbdev; | 1083 | struct usb_device* udev = cam->usbdev; |
1083 | u16 value; | 1084 | u16 value; |
1084 | int res; | 1085 | int res; |
1085 | 1086 | ||
1086 | value = *data++; | 1087 | value = *data++; |
1087 | 1088 | ||
1088 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | 1089 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, |
1089 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | 1090 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
1090 | value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); | 1091 | value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); |
1091 | 1092 | ||
1092 | if (res < 0) | 1093 | if (res < 0) |
1093 | DBG(4, "Failed to write the FSB registers " | 1094 | DBG(4, "Failed to write the FSB registers " |
1094 | "(error #%d, %s)", res, symbolic(urb_errlist, res)) | 1095 | "(error #%d, %s)", res, symbolic(urb_errlist, res)) |
1095 | 1096 | ||
1096 | return (res >= 0) ? 0 : -1; | 1097 | return (res >= 0) ? 0 : -1; |
1097 | } | 1098 | } |
1098 | 1099 | ||
1099 | 1100 | ||
1100 | /*-------------------------------------------------------------------------- | 1101 | /*-------------------------------------------------------------------------- |
1101 | Write data to the serial bus control register. | 1102 | Write data to the serial bus control register. |
1102 | Return 0 on success, a negative number otherwise. | 1103 | Return 0 on success, a negative number otherwise. |
1103 | --------------------------------------------------------------------------*/ | 1104 | --------------------------------------------------------------------------*/ |
1104 | static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) | 1105 | static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) |
1105 | { | 1106 | { |
1106 | int err = 0; | 1107 | int err = 0; |
1107 | 1108 | ||
1108 | err = w9968cf_write_reg(cam, value, 0x01); | 1109 | err = w9968cf_write_reg(cam, value, 0x01); |
1109 | udelay(W9968CF_I2C_BUS_DELAY); | 1110 | udelay(W9968CF_I2C_BUS_DELAY); |
1110 | 1111 | ||
1111 | return err; | 1112 | return err; |
1112 | } | 1113 | } |
1113 | 1114 | ||
1114 | 1115 | ||
1115 | /*-------------------------------------------------------------------------- | 1116 | /*-------------------------------------------------------------------------- |
1116 | Read data from the serial bus control register. | 1117 | Read data from the serial bus control register. |
1117 | Return 0 on success, a negative number otherwise. | 1118 | Return 0 on success, a negative number otherwise. |
1118 | --------------------------------------------------------------------------*/ | 1119 | --------------------------------------------------------------------------*/ |
1119 | static int w9968cf_read_sb(struct w9968cf_device* cam) | 1120 | static int w9968cf_read_sb(struct w9968cf_device* cam) |
1120 | { | 1121 | { |
1121 | int v = 0; | 1122 | int v = 0; |
1122 | 1123 | ||
1123 | v = w9968cf_read_reg(cam, 0x01); | 1124 | v = w9968cf_read_reg(cam, 0x01); |
1124 | udelay(W9968CF_I2C_BUS_DELAY); | 1125 | udelay(W9968CF_I2C_BUS_DELAY); |
1125 | 1126 | ||
1126 | return v; | 1127 | return v; |
1127 | } | 1128 | } |
1128 | 1129 | ||
1129 | 1130 | ||
1130 | /*-------------------------------------------------------------------------- | 1131 | /*-------------------------------------------------------------------------- |
1131 | Upload quantization tables for the JPEG compression. | 1132 | Upload quantization tables for the JPEG compression. |
1132 | This function is called by w9968cf_start_transfer(). | 1133 | This function is called by w9968cf_start_transfer(). |
1133 | Return 0 on success, a negative number otherwise. | 1134 | Return 0 on success, a negative number otherwise. |
1134 | --------------------------------------------------------------------------*/ | 1135 | --------------------------------------------------------------------------*/ |
1135 | static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) | 1136 | static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) |
1136 | { | 1137 | { |
1137 | u16 a, b; | 1138 | u16 a, b; |
1138 | int err = 0, i, j; | 1139 | int err = 0, i, j; |
1139 | 1140 | ||
1140 | err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ | 1141 | err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ |
1141 | 1142 | ||
1142 | for (i = 0, j = 0; i < 32; i++, j += 2) { | 1143 | for (i = 0, j = 0; i < 32; i++, j += 2) { |
1143 | a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); | 1144 | a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); |
1144 | b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); | 1145 | b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); |
1145 | err += w9968cf_write_reg(cam, a, 0x40+i); | 1146 | err += w9968cf_write_reg(cam, a, 0x40+i); |
1146 | err += w9968cf_write_reg(cam, b, 0x60+i); | 1147 | err += w9968cf_write_reg(cam, b, 0x60+i); |
1147 | } | 1148 | } |
1148 | err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ | 1149 | err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ |
1149 | 1150 | ||
1150 | return err; | 1151 | return err; |
1151 | } | 1152 | } |
1152 | 1153 | ||
1153 | 1154 | ||
1154 | 1155 | ||
1155 | /**************************************************************************** | 1156 | /**************************************************************************** |
1156 | * Low-level I2C I/O functions. * | 1157 | * Low-level I2C I/O functions. * |
1157 | * The adapter supports the following I2C transfer functions: * | 1158 | * The adapter supports the following I2C transfer functions: * |
1158 | * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * | 1159 | * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * |
1159 | * i2c_adap_read_byte_data() * | 1160 | * i2c_adap_read_byte_data() * |
1160 | * i2c_adap_read_byte() * | 1161 | * i2c_adap_read_byte() * |
1161 | ****************************************************************************/ | 1162 | ****************************************************************************/ |
1162 | 1163 | ||
1163 | static int w9968cf_smbus_start(struct w9968cf_device* cam) | 1164 | static int w9968cf_smbus_start(struct w9968cf_device* cam) |
1164 | { | 1165 | { |
1165 | int err = 0; | 1166 | int err = 0; |
1166 | 1167 | ||
1167 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | 1168 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ |
1168 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | 1169 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ |
1169 | 1170 | ||
1170 | return err; | 1171 | return err; |
1171 | } | 1172 | } |
1172 | 1173 | ||
1173 | 1174 | ||
1174 | static int w9968cf_smbus_stop(struct w9968cf_device* cam) | 1175 | static int w9968cf_smbus_stop(struct w9968cf_device* cam) |
1175 | { | 1176 | { |
1176 | int err = 0; | 1177 | int err = 0; |
1177 | 1178 | ||
1178 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | 1179 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ |
1179 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | 1180 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ |
1180 | 1181 | ||
1181 | return err; | 1182 | return err; |
1182 | } | 1183 | } |
1183 | 1184 | ||
1184 | 1185 | ||
1185 | static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) | 1186 | static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) |
1186 | { | 1187 | { |
1187 | u8 bit; | 1188 | u8 bit; |
1188 | int err = 0, sda; | 1189 | int err = 0, sda; |
1189 | 1190 | ||
1190 | for (bit = 0 ; bit < 8 ; bit++) { | 1191 | for (bit = 0 ; bit < 8 ; bit++) { |
1191 | sda = (v & 0x80) ? 2 : 0; | 1192 | sda = (v & 0x80) ? 2 : 0; |
1192 | v <<= 1; | 1193 | v <<= 1; |
1193 | /* SDE=1, SDA=sda, SCL=0 */ | 1194 | /* SDE=1, SDA=sda, SCL=0 */ |
1194 | err += w9968cf_write_sb(cam, 0x10 | sda); | 1195 | err += w9968cf_write_sb(cam, 0x10 | sda); |
1195 | /* SDE=1, SDA=sda, SCL=1 */ | 1196 | /* SDE=1, SDA=sda, SCL=1 */ |
1196 | err += w9968cf_write_sb(cam, 0x11 | sda); | 1197 | err += w9968cf_write_sb(cam, 0x11 | sda); |
1197 | /* SDE=1, SDA=sda, SCL=0 */ | 1198 | /* SDE=1, SDA=sda, SCL=0 */ |
1198 | err += w9968cf_write_sb(cam, 0x10 | sda); | 1199 | err += w9968cf_write_sb(cam, 0x10 | sda); |
1199 | } | 1200 | } |
1200 | 1201 | ||
1201 | return err; | 1202 | return err; |
1202 | } | 1203 | } |
1203 | 1204 | ||
1204 | 1205 | ||
1205 | static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) | 1206 | static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) |
1206 | { | 1207 | { |
1207 | u8 bit; | 1208 | u8 bit; |
1208 | int err = 0; | 1209 | int err = 0; |
1209 | 1210 | ||
1210 | *v = 0; | 1211 | *v = 0; |
1211 | for (bit = 0 ; bit < 8 ; bit++) { | 1212 | for (bit = 0 ; bit < 8 ; bit++) { |
1212 | *v <<= 1; | 1213 | *v <<= 1; |
1213 | err += w9968cf_write_sb(cam, 0x0013); | 1214 | err += w9968cf_write_sb(cam, 0x0013); |
1214 | *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; | 1215 | *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; |
1215 | err += w9968cf_write_sb(cam, 0x0012); | 1216 | err += w9968cf_write_sb(cam, 0x0012); |
1216 | } | 1217 | } |
1217 | 1218 | ||
1218 | return err; | 1219 | return err; |
1219 | } | 1220 | } |
1220 | 1221 | ||
1221 | 1222 | ||
1222 | static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) | 1223 | static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) |
1223 | { | 1224 | { |
1224 | int err = 0; | 1225 | int err = 0; |
1225 | 1226 | ||
1226 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | 1227 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ |
1227 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | 1228 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ |
1228 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | 1229 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ |
1229 | 1230 | ||
1230 | return err; | 1231 | return err; |
1231 | } | 1232 | } |
1232 | 1233 | ||
1233 | 1234 | ||
1234 | static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) | 1235 | static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) |
1235 | { | 1236 | { |
1236 | int err = 0, sda; | 1237 | int err = 0, sda; |
1237 | 1238 | ||
1238 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | 1239 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ |
1239 | sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ | 1240 | sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ |
1240 | err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ | 1241 | err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ |
1241 | if (sda < 0) | 1242 | if (sda < 0) |
1242 | err += sda; | 1243 | err += sda; |
1243 | if (sda == 1) { | 1244 | if (sda == 1) { |
1244 | DBG(6, "Couldn't receive the ACK") | 1245 | DBG(6, "Couldn't receive the ACK") |
1245 | err += -1; | 1246 | err += -1; |
1246 | } | 1247 | } |
1247 | 1248 | ||
1248 | return err; | 1249 | return err; |
1249 | } | 1250 | } |
1250 | 1251 | ||
1251 | 1252 | ||
1252 | /* This seems to refresh the communication through the serial bus */ | 1253 | /* This seems to refresh the communication through the serial bus */ |
1253 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) | 1254 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) |
1254 | { | 1255 | { |
1255 | int err = 0, j; | 1256 | int err = 0, j; |
1256 | 1257 | ||
1257 | for (j = 1; j <= 10; j++) { | 1258 | for (j = 1; j <= 10; j++) { |
1258 | err = w9968cf_write_reg(cam, 0x0020, 0x01); | 1259 | err = w9968cf_write_reg(cam, 0x0020, 0x01); |
1259 | err += w9968cf_write_reg(cam, 0x0000, 0x01); | 1260 | err += w9968cf_write_reg(cam, 0x0000, 0x01); |
1260 | if (err) | 1261 | if (err) |
1261 | break; | 1262 | break; |
1262 | } | 1263 | } |
1263 | 1264 | ||
1264 | return err; | 1265 | return err; |
1265 | } | 1266 | } |
1266 | 1267 | ||
1267 | 1268 | ||
1268 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ | 1269 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ |
1269 | static int | 1270 | static int |
1270 | w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, | 1271 | w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, |
1271 | u16 address, u8 subaddress,u8 value) | 1272 | u16 address, u8 subaddress,u8 value) |
1272 | { | 1273 | { |
1273 | u16* data = cam->data_buffer; | 1274 | u16* data = cam->data_buffer; |
1274 | int err = 0; | 1275 | int err = 0; |
1275 | 1276 | ||
1276 | err += w9968cf_smbus_refresh_bus(cam); | 1277 | err += w9968cf_smbus_refresh_bus(cam); |
1277 | 1278 | ||
1278 | /* Enable SBUS outputs */ | 1279 | /* Enable SBUS outputs */ |
1279 | err += w9968cf_write_sb(cam, 0x0020); | 1280 | err += w9968cf_write_sb(cam, 0x0020); |
1280 | 1281 | ||
1281 | data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); | 1282 | data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); |
1282 | data[0] |= (address & 0x40) ? 0x4000 : 0x0; | 1283 | data[0] |= (address & 0x40) ? 0x4000 : 0x0; |
1283 | data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); | 1284 | data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); |
1284 | data[1] |= (address & 0x20) ? 0x0150 : 0x0; | 1285 | data[1] |= (address & 0x20) ? 0x0150 : 0x0; |
1285 | data[1] |= (address & 0x10) ? 0x5400 : 0x0; | 1286 | data[1] |= (address & 0x10) ? 0x5400 : 0x0; |
1286 | data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); | 1287 | data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); |
1287 | data[2] |= (address & 0x04) ? 0x0540 : 0x0; | 1288 | data[2] |= (address & 0x04) ? 0x0540 : 0x0; |
1288 | data[2] |= (address & 0x02) ? 0x5000 : 0x0; | 1289 | data[2] |= (address & 0x02) ? 0x5000 : 0x0; |
1289 | data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); | 1290 | data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); |
1290 | data[3] |= (address & 0x01) ? 0x0054 : 0x0; | 1291 | data[3] |= (address & 0x01) ? 0x0054 : 0x0; |
1291 | 1292 | ||
1292 | err += w9968cf_write_fsb(cam, data); | 1293 | err += w9968cf_write_fsb(cam, data); |
1293 | 1294 | ||
1294 | data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); | 1295 | data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); |
1295 | data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; | 1296 | data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; |
1296 | data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; | 1297 | data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; |
1297 | data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); | 1298 | data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); |
1298 | data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; | 1299 | data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; |
1299 | data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; | 1300 | data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; |
1300 | data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; | 1301 | data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; |
1301 | data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); | 1302 | data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); |
1302 | data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; | 1303 | data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; |
1303 | data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; | 1304 | data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; |
1304 | data[3] = 0x001d; | 1305 | data[3] = 0x001d; |
1305 | 1306 | ||
1306 | err += w9968cf_write_fsb(cam, data); | 1307 | err += w9968cf_write_fsb(cam, data); |
1307 | 1308 | ||
1308 | data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); | 1309 | data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); |
1309 | data[0] |= (value & 0x40) ? 0x0540 : 0x0; | 1310 | data[0] |= (value & 0x40) ? 0x0540 : 0x0; |
1310 | data[0] |= (value & 0x20) ? 0x5000 : 0x0; | 1311 | data[0] |= (value & 0x20) ? 0x5000 : 0x0; |
1311 | data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); | 1312 | data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); |
1312 | data[1] |= (value & 0x10) ? 0x0054 : 0x0; | 1313 | data[1] |= (value & 0x10) ? 0x0054 : 0x0; |
1313 | data[1] |= (value & 0x08) ? 0x1500 : 0x0; | 1314 | data[1] |= (value & 0x08) ? 0x1500 : 0x0; |
1314 | data[1] |= (value & 0x04) ? 0x4000 : 0x0; | 1315 | data[1] |= (value & 0x04) ? 0x4000 : 0x0; |
1315 | data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); | 1316 | data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); |
1316 | data[2] |= (value & 0x02) ? 0x0150 : 0x0; | 1317 | data[2] |= (value & 0x02) ? 0x0150 : 0x0; |
1317 | data[2] |= (value & 0x01) ? 0x5400 : 0x0; | 1318 | data[2] |= (value & 0x01) ? 0x5400 : 0x0; |
1318 | data[3] = 0xfe1d; | 1319 | data[3] = 0xfe1d; |
1319 | 1320 | ||
1320 | err += w9968cf_write_fsb(cam, data); | 1321 | err += w9968cf_write_fsb(cam, data); |
1321 | 1322 | ||
1322 | /* Disable SBUS outputs */ | 1323 | /* Disable SBUS outputs */ |
1323 | err += w9968cf_write_sb(cam, 0x0000); | 1324 | err += w9968cf_write_sb(cam, 0x0000); |
1324 | 1325 | ||
1325 | if (!err) | 1326 | if (!err) |
1326 | DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " | 1327 | DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " |
1327 | "value 0x%02X", address, subaddress, value) | 1328 | "value 0x%02X", address, subaddress, value) |
1328 | else | 1329 | else |
1329 | DBG(5, "I2C write byte data failed, addr.0x%04X, " | 1330 | DBG(5, "I2C write byte data failed, addr.0x%04X, " |
1330 | "subaddr.0x%02X, value 0x%02X", | 1331 | "subaddr.0x%02X, value 0x%02X", |
1331 | address, subaddress, value) | 1332 | address, subaddress, value) |
1332 | 1333 | ||
1333 | return err; | 1334 | return err; |
1334 | } | 1335 | } |
1335 | 1336 | ||
1336 | 1337 | ||
1337 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ | 1338 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ |
1338 | static int | 1339 | static int |
1339 | w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, | 1340 | w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, |
1340 | u16 address, u8 subaddress, | 1341 | u16 address, u8 subaddress, |
1341 | u8* value) | 1342 | u8* value) |
1342 | { | 1343 | { |
1343 | int err = 0; | 1344 | int err = 0; |
1344 | 1345 | ||
1345 | /* Serial data enable */ | 1346 | /* Serial data enable */ |
1346 | err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ | 1347 | err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ |
1347 | 1348 | ||
1348 | err += w9968cf_smbus_start(cam); | 1349 | err += w9968cf_smbus_start(cam); |
1349 | err += w9968cf_smbus_write_byte(cam, address); | 1350 | err += w9968cf_smbus_write_byte(cam, address); |
1350 | err += w9968cf_smbus_read_ack(cam); | 1351 | err += w9968cf_smbus_read_ack(cam); |
1351 | err += w9968cf_smbus_write_byte(cam, subaddress); | 1352 | err += w9968cf_smbus_write_byte(cam, subaddress); |
1352 | err += w9968cf_smbus_read_ack(cam); | 1353 | err += w9968cf_smbus_read_ack(cam); |
1353 | err += w9968cf_smbus_stop(cam); | 1354 | err += w9968cf_smbus_stop(cam); |
1354 | err += w9968cf_smbus_start(cam); | 1355 | err += w9968cf_smbus_start(cam); |
1355 | err += w9968cf_smbus_write_byte(cam, address + 1); | 1356 | err += w9968cf_smbus_write_byte(cam, address + 1); |
1356 | err += w9968cf_smbus_read_ack(cam); | 1357 | err += w9968cf_smbus_read_ack(cam); |
1357 | err += w9968cf_smbus_read_byte(cam, value); | 1358 | err += w9968cf_smbus_read_byte(cam, value); |
1358 | err += w9968cf_smbus_write_ack(cam); | 1359 | err += w9968cf_smbus_write_ack(cam); |
1359 | err += w9968cf_smbus_stop(cam); | 1360 | err += w9968cf_smbus_stop(cam); |
1360 | 1361 | ||
1361 | /* Serial data disable */ | 1362 | /* Serial data disable */ |
1362 | err += w9968cf_write_sb(cam, 0x0000); | 1363 | err += w9968cf_write_sb(cam, 0x0000); |
1363 | 1364 | ||
1364 | if (!err) | 1365 | if (!err) |
1365 | DBG(5, "I2C read byte data done, addr.0x%04X, " | 1366 | DBG(5, "I2C read byte data done, addr.0x%04X, " |
1366 | "subaddr.0x%02X, value 0x%02X", | 1367 | "subaddr.0x%02X, value 0x%02X", |
1367 | address, subaddress, *value) | 1368 | address, subaddress, *value) |
1368 | else | 1369 | else |
1369 | DBG(5, "I2C read byte data failed, addr.0x%04X, " | 1370 | DBG(5, "I2C read byte data failed, addr.0x%04X, " |
1370 | "subaddr.0x%02X, wrong value 0x%02X", | 1371 | "subaddr.0x%02X, wrong value 0x%02X", |
1371 | address, subaddress, *value) | 1372 | address, subaddress, *value) |
1372 | 1373 | ||
1373 | return err; | 1374 | return err; |
1374 | } | 1375 | } |
1375 | 1376 | ||
1376 | 1377 | ||
1377 | /* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ | 1378 | /* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ |
1378 | static int | 1379 | static int |
1379 | w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | 1380 | w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, |
1380 | u16 address, u8* value) | 1381 | u16 address, u8* value) |
1381 | { | 1382 | { |
1382 | int err = 0; | 1383 | int err = 0; |
1383 | 1384 | ||
1384 | /* Serial data enable */ | 1385 | /* Serial data enable */ |
1385 | err += w9968cf_write_sb(cam, 0x0013); | 1386 | err += w9968cf_write_sb(cam, 0x0013); |
1386 | 1387 | ||
1387 | err += w9968cf_smbus_start(cam); | 1388 | err += w9968cf_smbus_start(cam); |
1388 | err += w9968cf_smbus_write_byte(cam, address + 1); | 1389 | err += w9968cf_smbus_write_byte(cam, address + 1); |
1389 | err += w9968cf_smbus_read_ack(cam); | 1390 | err += w9968cf_smbus_read_ack(cam); |
1390 | err += w9968cf_smbus_read_byte(cam, value); | 1391 | err += w9968cf_smbus_read_byte(cam, value); |
1391 | err += w9968cf_smbus_write_ack(cam); | 1392 | err += w9968cf_smbus_write_ack(cam); |
1392 | err += w9968cf_smbus_stop(cam); | 1393 | err += w9968cf_smbus_stop(cam); |
1393 | 1394 | ||
1394 | /* Serial data disable */ | 1395 | /* Serial data disable */ |
1395 | err += w9968cf_write_sb(cam, 0x0000); | 1396 | err += w9968cf_write_sb(cam, 0x0000); |
1396 | 1397 | ||
1397 | if (!err) | 1398 | if (!err) |
1398 | DBG(5, "I2C read byte done, addr.0x%04X, " | 1399 | DBG(5, "I2C read byte done, addr.0x%04X, " |
1399 | "value 0x%02X", address, *value) | 1400 | "value 0x%02X", address, *value) |
1400 | else | 1401 | else |
1401 | DBG(5, "I2C read byte failed, addr.0x%04X, " | 1402 | DBG(5, "I2C read byte failed, addr.0x%04X, " |
1402 | "wrong value 0x%02X", address, *value) | 1403 | "wrong value 0x%02X", address, *value) |
1403 | 1404 | ||
1404 | return err; | 1405 | return err; |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | 1408 | ||
1408 | /* SMBus protocol: S Addr Wr [A] Value [A] P */ | 1409 | /* SMBus protocol: S Addr Wr [A] Value [A] P */ |
1409 | static int | 1410 | static int |
1410 | w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, | 1411 | w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, |
1411 | u16 address, u8 value) | 1412 | u16 address, u8 value) |
1412 | { | 1413 | { |
1413 | DBG(4, "i2c_write_byte() is an unsupported transfer mode") | 1414 | DBG(4, "i2c_write_byte() is an unsupported transfer mode") |
1414 | return -EINVAL; | 1415 | return -EINVAL; |
1415 | } | 1416 | } |
1416 | 1417 | ||
1417 | 1418 | ||
1418 | 1419 | ||
1419 | /**************************************************************************** | 1420 | /**************************************************************************** |
1420 | * I2C interface to kernel * | 1421 | * I2C interface to kernel * |
1421 | ****************************************************************************/ | 1422 | ****************************************************************************/ |
1422 | 1423 | ||
1423 | static int | 1424 | static int |
1424 | w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | 1425 | w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, |
1425 | unsigned short flags, char read_write, u8 command, | 1426 | unsigned short flags, char read_write, u8 command, |
1426 | int size, union i2c_smbus_data *data) | 1427 | int size, union i2c_smbus_data *data) |
1427 | { | 1428 | { |
1428 | struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); | 1429 | struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); |
1429 | struct w9968cf_device *cam = to_cam(v4l2_dev); | 1430 | struct w9968cf_device *cam = to_cam(v4l2_dev); |
1430 | u8 i; | 1431 | u8 i; |
1431 | int err = 0; | 1432 | int err = 0; |
1432 | 1433 | ||
1433 | if (size == I2C_SMBUS_BYTE) { | 1434 | if (size == I2C_SMBUS_BYTE) { |
1434 | /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ | 1435 | /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ |
1435 | addr <<= 1; | 1436 | addr <<= 1; |
1436 | 1437 | ||
1437 | if (read_write == I2C_SMBUS_WRITE) | 1438 | if (read_write == I2C_SMBUS_WRITE) |
1438 | err = w9968cf_i2c_adap_write_byte(cam, addr, command); | 1439 | err = w9968cf_i2c_adap_write_byte(cam, addr, command); |
1439 | else if (read_write == I2C_SMBUS_READ) | 1440 | else if (read_write == I2C_SMBUS_READ) |
1440 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { | 1441 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { |
1441 | err = w9968cf_i2c_adap_read_byte(cam, addr, | 1442 | err = w9968cf_i2c_adap_read_byte(cam, addr, |
1442 | &data->byte); | 1443 | &data->byte); |
1443 | if (err) { | 1444 | if (err) { |
1444 | if (w9968cf_smbus_refresh_bus(cam)) { | 1445 | if (w9968cf_smbus_refresh_bus(cam)) { |
1445 | err = -EIO; | 1446 | err = -EIO; |
1446 | break; | 1447 | break; |
1447 | } | 1448 | } |
1448 | } else | 1449 | } else |
1449 | break; | 1450 | break; |
1450 | } | 1451 | } |
1451 | } else if (size == I2C_SMBUS_BYTE_DATA) { | 1452 | } else if (size == I2C_SMBUS_BYTE_DATA) { |
1452 | addr <<= 1; | 1453 | addr <<= 1; |
1453 | 1454 | ||
1454 | if (read_write == I2C_SMBUS_WRITE) | 1455 | if (read_write == I2C_SMBUS_WRITE) |
1455 | err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, | 1456 | err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, |
1456 | command, data->byte); | 1457 | command, data->byte); |
1457 | else if (read_write == I2C_SMBUS_READ) { | 1458 | else if (read_write == I2C_SMBUS_READ) { |
1458 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { | 1459 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { |
1459 | err = w9968cf_i2c_adap_read_byte_data(cam,addr, | 1460 | err = w9968cf_i2c_adap_read_byte_data(cam,addr, |
1460 | command, &data->byte); | 1461 | command, &data->byte); |
1461 | if (err) { | 1462 | if (err) { |
1462 | if (w9968cf_smbus_refresh_bus(cam)) { | 1463 | if (w9968cf_smbus_refresh_bus(cam)) { |
1463 | err = -EIO; | 1464 | err = -EIO; |
1464 | break; | 1465 | break; |
1465 | } | 1466 | } |
1466 | } else | 1467 | } else |
1467 | break; | 1468 | break; |
1468 | } | 1469 | } |
1469 | 1470 | ||
1470 | } else | 1471 | } else |
1471 | return -EINVAL; | 1472 | return -EINVAL; |
1472 | 1473 | ||
1473 | } else { | 1474 | } else { |
1474 | DBG(4, "Unsupported I2C transfer mode (%d)", size) | 1475 | DBG(4, "Unsupported I2C transfer mode (%d)", size) |
1475 | return -EINVAL; | 1476 | return -EINVAL; |
1476 | } | 1477 | } |
1477 | return err; | 1478 | return err; |
1478 | } | 1479 | } |
1479 | 1480 | ||
1480 | 1481 | ||
1481 | static u32 w9968cf_i2c_func(struct i2c_adapter* adap) | 1482 | static u32 w9968cf_i2c_func(struct i2c_adapter* adap) |
1482 | { | 1483 | { |
1483 | return I2C_FUNC_SMBUS_READ_BYTE | | 1484 | return I2C_FUNC_SMBUS_READ_BYTE | |
1484 | I2C_FUNC_SMBUS_READ_BYTE_DATA | | 1485 | I2C_FUNC_SMBUS_READ_BYTE_DATA | |
1485 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | 1486 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; |
1486 | } | 1487 | } |
1487 | 1488 | ||
1488 | 1489 | ||
1489 | static int w9968cf_i2c_init(struct w9968cf_device* cam) | 1490 | static int w9968cf_i2c_init(struct w9968cf_device* cam) |
1490 | { | 1491 | { |
1491 | int err = 0; | 1492 | int err = 0; |
1492 | 1493 | ||
1493 | static struct i2c_algorithm algo = { | 1494 | static struct i2c_algorithm algo = { |
1494 | .smbus_xfer = w9968cf_i2c_smbus_xfer, | 1495 | .smbus_xfer = w9968cf_i2c_smbus_xfer, |
1495 | .functionality = w9968cf_i2c_func, | 1496 | .functionality = w9968cf_i2c_func, |
1496 | }; | 1497 | }; |
1497 | 1498 | ||
1498 | static struct i2c_adapter adap = { | 1499 | static struct i2c_adapter adap = { |
1499 | .id = I2C_HW_SMBUS_W9968CF, | 1500 | .id = I2C_HW_SMBUS_W9968CF, |
1500 | .owner = THIS_MODULE, | 1501 | .owner = THIS_MODULE, |
1501 | .algo = &algo, | 1502 | .algo = &algo, |
1502 | }; | 1503 | }; |
1503 | 1504 | ||
1504 | memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); | 1505 | memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); |
1505 | strcpy(cam->i2c_adapter.name, "w9968cf"); | 1506 | strcpy(cam->i2c_adapter.name, "w9968cf"); |
1506 | cam->i2c_adapter.dev.parent = &cam->usbdev->dev; | 1507 | cam->i2c_adapter.dev.parent = &cam->usbdev->dev; |
1507 | i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev); | 1508 | i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev); |
1508 | 1509 | ||
1509 | DBG(6, "Registering I2C adapter with kernel...") | 1510 | DBG(6, "Registering I2C adapter with kernel...") |
1510 | 1511 | ||
1511 | err = i2c_add_adapter(&cam->i2c_adapter); | 1512 | err = i2c_add_adapter(&cam->i2c_adapter); |
1512 | if (err) | 1513 | if (err) |
1513 | DBG(1, "Failed to register the I2C adapter") | 1514 | DBG(1, "Failed to register the I2C adapter") |
1514 | else | 1515 | else |
1515 | DBG(5, "I2C adapter registered") | 1516 | DBG(5, "I2C adapter registered") |
1516 | 1517 | ||
1517 | return err; | 1518 | return err; |
1518 | } | 1519 | } |
1519 | 1520 | ||
1520 | 1521 | ||
1521 | 1522 | ||
1522 | /**************************************************************************** | 1523 | /**************************************************************************** |
1523 | * Helper functions * | 1524 | * Helper functions * |
1524 | ****************************************************************************/ | 1525 | ****************************************************************************/ |
1525 | 1526 | ||
1526 | /*-------------------------------------------------------------------------- | 1527 | /*-------------------------------------------------------------------------- |
1527 | Turn on the LED on some webcams. A beep should be heard too. | 1528 | Turn on the LED on some webcams. A beep should be heard too. |
1528 | Return 0 on success, a negative number otherwise. | 1529 | Return 0 on success, a negative number otherwise. |
1529 | --------------------------------------------------------------------------*/ | 1530 | --------------------------------------------------------------------------*/ |
1530 | static int w9968cf_turn_on_led(struct w9968cf_device* cam) | 1531 | static int w9968cf_turn_on_led(struct w9968cf_device* cam) |
1531 | { | 1532 | { |
1532 | int err = 0; | 1533 | int err = 0; |
1533 | 1534 | ||
1534 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ | 1535 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ |
1535 | err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | 1536 | err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ |
1536 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | 1537 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ |
1537 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ | 1538 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ |
1538 | err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ | 1539 | err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ |
1539 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ | 1540 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ |
1540 | 1541 | ||
1541 | if (err) | 1542 | if (err) |
1542 | DBG(2, "Couldn't turn on the LED") | 1543 | DBG(2, "Couldn't turn on the LED") |
1543 | 1544 | ||
1544 | DBG(5, "LED turned on") | 1545 | DBG(5, "LED turned on") |
1545 | 1546 | ||
1546 | return err; | 1547 | return err; |
1547 | } | 1548 | } |
1548 | 1549 | ||
1549 | 1550 | ||
1550 | /*-------------------------------------------------------------------------- | 1551 | /*-------------------------------------------------------------------------- |
1551 | Write some registers for the device initialization. | 1552 | Write some registers for the device initialization. |
1552 | This function is called once on open(). | 1553 | This function is called once on open(). |
1553 | Return 0 on success, a negative number otherwise. | 1554 | Return 0 on success, a negative number otherwise. |
1554 | --------------------------------------------------------------------------*/ | 1555 | --------------------------------------------------------------------------*/ |
1555 | static int w9968cf_init_chip(struct w9968cf_device* cam) | 1556 | static int w9968cf_init_chip(struct w9968cf_device* cam) |
1556 | { | 1557 | { |
1557 | unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, | 1558 | unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, |
1558 | y0 = 0x0000, | 1559 | y0 = 0x0000, |
1559 | u0 = y0 + hw_bufsize/2, | 1560 | u0 = y0 + hw_bufsize/2, |
1560 | v0 = u0 + hw_bufsize/4, | 1561 | v0 = u0 + hw_bufsize/4, |
1561 | y1 = v0 + hw_bufsize/4, | 1562 | y1 = v0 + hw_bufsize/4, |
1562 | u1 = y1 + hw_bufsize/2, | 1563 | u1 = y1 + hw_bufsize/2, |
1563 | v1 = u1 + hw_bufsize/4; | 1564 | v1 = u1 + hw_bufsize/4; |
1564 | int err = 0; | 1565 | int err = 0; |
1565 | 1566 | ||
1566 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ | 1567 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ |
1567 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ | 1568 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ |
1568 | 1569 | ||
1569 | err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ | 1570 | err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ |
1570 | err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ | 1571 | err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ |
1571 | 1572 | ||
1572 | err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ | 1573 | err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ |
1573 | err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ | 1574 | err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ |
1574 | err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ | 1575 | err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ |
1575 | err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ | 1576 | err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ |
1576 | err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ | 1577 | err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ |
1577 | err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ | 1578 | err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ |
1578 | 1579 | ||
1579 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ | 1580 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ |
1580 | err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ | 1581 | err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ |
1581 | err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ | 1582 | err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ |
1582 | err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ | 1583 | err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ |
1583 | err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ | 1584 | err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ |
1584 | err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ | 1585 | err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ |
1585 | 1586 | ||
1586 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ | 1587 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ |
1587 | err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ | 1588 | err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ |
1588 | 1589 | ||
1589 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ | 1590 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ |
1590 | err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ | 1591 | err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ |
1591 | 1592 | ||
1592 | err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ | 1593 | err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ |
1593 | err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ | 1594 | err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ |
1594 | err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ | 1595 | err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ |
1595 | err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ | 1596 | err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ |
1596 | 1597 | ||
1597 | err += w9968cf_set_picture(cam, cam->picture); /* this before */ | 1598 | err += w9968cf_set_picture(cam, cam->picture); /* this before */ |
1598 | err += w9968cf_set_window(cam, cam->window); | 1599 | err += w9968cf_set_window(cam, cam->window); |
1599 | 1600 | ||
1600 | if (err) | 1601 | if (err) |
1601 | DBG(1, "Chip initialization failed") | 1602 | DBG(1, "Chip initialization failed") |
1602 | else | 1603 | else |
1603 | DBG(5, "Chip successfully initialized") | 1604 | DBG(5, "Chip successfully initialized") |
1604 | 1605 | ||
1605 | return err; | 1606 | return err; |
1606 | } | 1607 | } |
1607 | 1608 | ||
1608 | 1609 | ||
1609 | /*-------------------------------------------------------------------------- | 1610 | /*-------------------------------------------------------------------------- |
1610 | Return non-zero if the palette is supported, 0 otherwise. | 1611 | Return non-zero if the palette is supported, 0 otherwise. |
1611 | --------------------------------------------------------------------------*/ | 1612 | --------------------------------------------------------------------------*/ |
1612 | static inline u16 w9968cf_valid_palette(u16 palette) | 1613 | static inline u16 w9968cf_valid_palette(u16 palette) |
1613 | { | 1614 | { |
1614 | u8 i = 0; | 1615 | u8 i = 0; |
1615 | while (w9968cf_formatlist[i].palette != 0) { | 1616 | while (w9968cf_formatlist[i].palette != 0) { |
1616 | if (palette == w9968cf_formatlist[i].palette) | 1617 | if (palette == w9968cf_formatlist[i].palette) |
1617 | return palette; | 1618 | return palette; |
1618 | i++; | 1619 | i++; |
1619 | } | 1620 | } |
1620 | return 0; | 1621 | return 0; |
1621 | } | 1622 | } |
1622 | 1623 | ||
1623 | 1624 | ||
1624 | /*-------------------------------------------------------------------------- | 1625 | /*-------------------------------------------------------------------------- |
1625 | Return the depth corresponding to the given palette. | 1626 | Return the depth corresponding to the given palette. |
1626 | Palette _must_ be supported ! | 1627 | Palette _must_ be supported ! |
1627 | --------------------------------------------------------------------------*/ | 1628 | --------------------------------------------------------------------------*/ |
1628 | static inline u16 w9968cf_valid_depth(u16 palette) | 1629 | static inline u16 w9968cf_valid_depth(u16 palette) |
1629 | { | 1630 | { |
1630 | u8 i=0; | 1631 | u8 i=0; |
1631 | while (w9968cf_formatlist[i].palette != palette) | 1632 | while (w9968cf_formatlist[i].palette != palette) |
1632 | i++; | 1633 | i++; |
1633 | 1634 | ||
1634 | return w9968cf_formatlist[i].depth; | 1635 | return w9968cf_formatlist[i].depth; |
1635 | } | 1636 | } |
1636 | 1637 | ||
1637 | 1638 | ||
1638 | /*-------------------------------------------------------------------------- | 1639 | /*-------------------------------------------------------------------------- |
1639 | Return non-zero if the format requires decompression, 0 otherwise. | 1640 | Return non-zero if the format requires decompression, 0 otherwise. |
1640 | --------------------------------------------------------------------------*/ | 1641 | --------------------------------------------------------------------------*/ |
1641 | static inline u8 w9968cf_need_decompression(u16 palette) | 1642 | static inline u8 w9968cf_need_decompression(u16 palette) |
1642 | { | 1643 | { |
1643 | u8 i = 0; | 1644 | u8 i = 0; |
1644 | while (w9968cf_formatlist[i].palette != 0) { | 1645 | while (w9968cf_formatlist[i].palette != 0) { |
1645 | if (palette == w9968cf_formatlist[i].palette) | 1646 | if (palette == w9968cf_formatlist[i].palette) |
1646 | return w9968cf_formatlist[i].compression; | 1647 | return w9968cf_formatlist[i].compression; |
1647 | i++; | 1648 | i++; |
1648 | } | 1649 | } |
1649 | return 0; | 1650 | return 0; |
1650 | } | 1651 | } |
1651 | 1652 | ||
1652 | 1653 | ||
1653 | /*-------------------------------------------------------------------------- | 1654 | /*-------------------------------------------------------------------------- |
1654 | Change the picture settings of the camera. | 1655 | Change the picture settings of the camera. |
1655 | Return 0 on success, a negative number otherwise. | 1656 | Return 0 on success, a negative number otherwise. |
1656 | --------------------------------------------------------------------------*/ | 1657 | --------------------------------------------------------------------------*/ |
1657 | static int | 1658 | static int |
1658 | w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) | 1659 | w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) |
1659 | { | 1660 | { |
1660 | u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; | 1661 | u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; |
1661 | int err = 0; | 1662 | int err = 0; |
1662 | 1663 | ||
1663 | /* Make sure we are using a valid depth */ | 1664 | /* Make sure we are using a valid depth */ |
1664 | pict.depth = w9968cf_valid_depth(pict.palette); | 1665 | pict.depth = w9968cf_valid_depth(pict.palette); |
1665 | 1666 | ||
1666 | fmt = pict.palette; | 1667 | fmt = pict.palette; |
1667 | 1668 | ||
1668 | hw_depth = pict.depth; /* depth used by the winbond chip */ | 1669 | hw_depth = pict.depth; /* depth used by the winbond chip */ |
1669 | hw_palette = pict.palette; /* palette used by the winbond chip */ | 1670 | hw_palette = pict.palette; /* palette used by the winbond chip */ |
1670 | 1671 | ||
1671 | /* VS & HS polarities */ | 1672 | /* VS & HS polarities */ |
1672 | reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); | 1673 | reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); |
1673 | 1674 | ||
1674 | switch (fmt) | 1675 | switch (fmt) |
1675 | { | 1676 | { |
1676 | case VIDEO_PALETTE_UYVY: | 1677 | case VIDEO_PALETTE_UYVY: |
1677 | reg_v |= 0x0000; | 1678 | reg_v |= 0x0000; |
1678 | cam->vpp_flag = VPP_NONE; | 1679 | cam->vpp_flag = VPP_NONE; |
1679 | break; | 1680 | break; |
1680 | case VIDEO_PALETTE_YUV422P: | 1681 | case VIDEO_PALETTE_YUV422P: |
1681 | reg_v |= 0x0002; | 1682 | reg_v |= 0x0002; |
1682 | cam->vpp_flag = VPP_DECOMPRESSION; | 1683 | cam->vpp_flag = VPP_DECOMPRESSION; |
1683 | break; | 1684 | break; |
1684 | case VIDEO_PALETTE_YUV420: | 1685 | case VIDEO_PALETTE_YUV420: |
1685 | case VIDEO_PALETTE_YUV420P: | 1686 | case VIDEO_PALETTE_YUV420P: |
1686 | reg_v |= 0x0003; | 1687 | reg_v |= 0x0003; |
1687 | cam->vpp_flag = VPP_DECOMPRESSION; | 1688 | cam->vpp_flag = VPP_DECOMPRESSION; |
1688 | break; | 1689 | break; |
1689 | case VIDEO_PALETTE_YUYV: | 1690 | case VIDEO_PALETTE_YUYV: |
1690 | case VIDEO_PALETTE_YUV422: | 1691 | case VIDEO_PALETTE_YUV422: |
1691 | reg_v |= 0x0000; | 1692 | reg_v |= 0x0000; |
1692 | cam->vpp_flag = VPP_SWAP_YUV_BYTES; | 1693 | cam->vpp_flag = VPP_SWAP_YUV_BYTES; |
1693 | hw_palette = VIDEO_PALETTE_UYVY; | 1694 | hw_palette = VIDEO_PALETTE_UYVY; |
1694 | break; | 1695 | break; |
1695 | /* Original video is used instead of RGBX palettes. | 1696 | /* Original video is used instead of RGBX palettes. |
1696 | Software conversion later. */ | 1697 | Software conversion later. */ |
1697 | case VIDEO_PALETTE_GREY: | 1698 | case VIDEO_PALETTE_GREY: |
1698 | case VIDEO_PALETTE_RGB555: | 1699 | case VIDEO_PALETTE_RGB555: |
1699 | case VIDEO_PALETTE_RGB565: | 1700 | case VIDEO_PALETTE_RGB565: |
1700 | case VIDEO_PALETTE_RGB24: | 1701 | case VIDEO_PALETTE_RGB24: |
1701 | case VIDEO_PALETTE_RGB32: | 1702 | case VIDEO_PALETTE_RGB32: |
1702 | reg_v |= 0x0000; /* UYVY 16 bit is used */ | 1703 | reg_v |= 0x0000; /* UYVY 16 bit is used */ |
1703 | hw_depth = 16; | 1704 | hw_depth = 16; |
1704 | hw_palette = VIDEO_PALETTE_UYVY; | 1705 | hw_palette = VIDEO_PALETTE_UYVY; |
1705 | cam->vpp_flag = VPP_UYVY_TO_RGBX; | 1706 | cam->vpp_flag = VPP_UYVY_TO_RGBX; |
1706 | break; | 1707 | break; |
1707 | } | 1708 | } |
1708 | 1709 | ||
1709 | /* NOTE: due to memory issues, it is better to disable the hardware | 1710 | /* NOTE: due to memory issues, it is better to disable the hardware |
1710 | double buffering during compression */ | 1711 | double buffering during compression */ |
1711 | if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) | 1712 | if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) |
1712 | reg_v |= 0x0080; | 1713 | reg_v |= 0x0080; |
1713 | 1714 | ||
1714 | if (cam->clamping) | 1715 | if (cam->clamping) |
1715 | reg_v |= 0x0020; | 1716 | reg_v |= 0x0020; |
1716 | 1717 | ||
1717 | if (cam->filter_type == 1) | 1718 | if (cam->filter_type == 1) |
1718 | reg_v |= 0x0008; | 1719 | reg_v |= 0x0008; |
1719 | else if (cam->filter_type == 2) | 1720 | else if (cam->filter_type == 2) |
1720 | reg_v |= 0x000c; | 1721 | reg_v |= 0x000c; |
1721 | 1722 | ||
1722 | if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) | 1723 | if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) |
1723 | goto error; | 1724 | goto error; |
1724 | 1725 | ||
1725 | if ((err = w9968cf_sensor_update_picture(cam, pict))) | 1726 | if ((err = w9968cf_sensor_update_picture(cam, pict))) |
1726 | goto error; | 1727 | goto error; |
1727 | 1728 | ||
1728 | /* If all went well, update the device data structure */ | 1729 | /* If all went well, update the device data structure */ |
1729 | memcpy(&cam->picture, &pict, sizeof(pict)); | 1730 | memcpy(&cam->picture, &pict, sizeof(pict)); |
1730 | cam->hw_depth = hw_depth; | 1731 | cam->hw_depth = hw_depth; |
1731 | cam->hw_palette = hw_palette; | 1732 | cam->hw_palette = hw_palette; |
1732 | 1733 | ||
1733 | /* Settings changed, so we clear the frame buffers */ | 1734 | /* Settings changed, so we clear the frame buffers */ |
1734 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | 1735 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); |
1735 | 1736 | ||
1736 | DBG(4, "Palette is %s, depth is %u bpp", | 1737 | DBG(4, "Palette is %s, depth is %u bpp", |
1737 | symbolic(v4l1_plist, pict.palette), pict.depth) | 1738 | symbolic(v4l1_plist, pict.palette), pict.depth) |
1738 | 1739 | ||
1739 | return 0; | 1740 | return 0; |
1740 | 1741 | ||
1741 | error: | 1742 | error: |
1742 | DBG(1, "Failed to change picture settings") | 1743 | DBG(1, "Failed to change picture settings") |
1743 | return err; | 1744 | return err; |
1744 | } | 1745 | } |
1745 | 1746 | ||
1746 | 1747 | ||
1747 | /*-------------------------------------------------------------------------- | 1748 | /*-------------------------------------------------------------------------- |
1748 | Change the capture area size of the camera. | 1749 | Change the capture area size of the camera. |
1749 | This function _must_ be called _after_ w9968cf_set_picture(). | 1750 | This function _must_ be called _after_ w9968cf_set_picture(). |
1750 | Return 0 on success, a negative number otherwise. | 1751 | Return 0 on success, a negative number otherwise. |
1751 | --------------------------------------------------------------------------*/ | 1752 | --------------------------------------------------------------------------*/ |
1752 | static int | 1753 | static int |
1753 | w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) | 1754 | w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) |
1754 | { | 1755 | { |
1755 | u16 x, y, w, h, scx, scy, cw, ch, ax, ay; | 1756 | u16 x, y, w, h, scx, scy, cw, ch, ax, ay; |
1756 | unsigned long fw, fh; | 1757 | unsigned long fw, fh; |
1757 | struct ovcamchip_window s_win; | 1758 | struct ovcamchip_window s_win; |
1758 | int err = 0; | 1759 | int err = 0; |
1759 | 1760 | ||
1760 | /* Work around to avoid FP arithmetics */ | 1761 | /* Work around to avoid FP arithmetics */ |
1761 | #define SC(x) ((x) << 10) | 1762 | #define SC(x) ((x) << 10) |
1762 | #define UNSC(x) ((x) >> 10) | 1763 | #define UNSC(x) ((x) >> 10) |
1763 | 1764 | ||
1764 | /* Make sure we are using a supported resolution */ | 1765 | /* Make sure we are using a supported resolution */ |
1765 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | 1766 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, |
1766 | (u16*)&win.height))) | 1767 | (u16*)&win.height))) |
1767 | goto error; | 1768 | goto error; |
1768 | 1769 | ||
1769 | /* Scaling factors */ | 1770 | /* Scaling factors */ |
1770 | fw = SC(win.width) / cam->maxwidth; | 1771 | fw = SC(win.width) / cam->maxwidth; |
1771 | fh = SC(win.height) / cam->maxheight; | 1772 | fh = SC(win.height) / cam->maxheight; |
1772 | 1773 | ||
1773 | /* Set up the width and height values used by the chip */ | 1774 | /* Set up the width and height values used by the chip */ |
1774 | if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { | 1775 | if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { |
1775 | cam->vpp_flag |= VPP_UPSCALE; | 1776 | cam->vpp_flag |= VPP_UPSCALE; |
1776 | /* Calculate largest w,h mantaining the same w/h ratio */ | 1777 | /* Calculate largest w,h mantaining the same w/h ratio */ |
1777 | w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; | 1778 | w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; |
1778 | h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; | 1779 | h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; |
1779 | if (w < cam->minwidth) /* just in case */ | 1780 | if (w < cam->minwidth) /* just in case */ |
1780 | w = cam->minwidth; | 1781 | w = cam->minwidth; |
1781 | if (h < cam->minheight) /* just in case */ | 1782 | if (h < cam->minheight) /* just in case */ |
1782 | h = cam->minheight; | 1783 | h = cam->minheight; |
1783 | } else { | 1784 | } else { |
1784 | cam->vpp_flag &= ~VPP_UPSCALE; | 1785 | cam->vpp_flag &= ~VPP_UPSCALE; |
1785 | w = win.width; | 1786 | w = win.width; |
1786 | h = win.height; | 1787 | h = win.height; |
1787 | } | 1788 | } |
1788 | 1789 | ||
1789 | /* x,y offsets of the cropped area */ | 1790 | /* x,y offsets of the cropped area */ |
1790 | scx = cam->start_cropx; | 1791 | scx = cam->start_cropx; |
1791 | scy = cam->start_cropy; | 1792 | scy = cam->start_cropy; |
1792 | 1793 | ||
1793 | /* Calculate cropped area manteining the right w/h ratio */ | 1794 | /* Calculate cropped area manteining the right w/h ratio */ |
1794 | if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { | 1795 | if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { |
1795 | cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; | 1796 | cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh; |
1796 | ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; | 1797 | ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight; |
1797 | } else { | 1798 | } else { |
1798 | cw = w; | 1799 | cw = w; |
1799 | ch = h; | 1800 | ch = h; |
1800 | } | 1801 | } |
1801 | 1802 | ||
1802 | /* Setup the window of the sensor */ | 1803 | /* Setup the window of the sensor */ |
1803 | s_win.format = VIDEO_PALETTE_UYVY; | 1804 | s_win.format = VIDEO_PALETTE_UYVY; |
1804 | s_win.width = cam->maxwidth; | 1805 | s_win.width = cam->maxwidth; |
1805 | s_win.height = cam->maxheight; | 1806 | s_win.height = cam->maxheight; |
1806 | s_win.quarter = 0; /* full progressive video */ | 1807 | s_win.quarter = 0; /* full progressive video */ |
1807 | 1808 | ||
1808 | /* Center it */ | 1809 | /* Center it */ |
1809 | s_win.x = (s_win.width - cw) / 2; | 1810 | s_win.x = (s_win.width - cw) / 2; |
1810 | s_win.y = (s_win.height - ch) / 2; | 1811 | s_win.y = (s_win.height - ch) / 2; |
1811 | 1812 | ||
1812 | /* Clock divisor */ | 1813 | /* Clock divisor */ |
1813 | if (cam->clockdiv >= 0) | 1814 | if (cam->clockdiv >= 0) |
1814 | s_win.clockdiv = cam->clockdiv; /* manual override */ | 1815 | s_win.clockdiv = cam->clockdiv; /* manual override */ |
1815 | else | 1816 | else |
1816 | switch (cam->sensor) { | 1817 | switch (cam->sensor) { |
1817 | case CC_OV6620: | 1818 | case CC_OV6620: |
1818 | s_win.clockdiv = 0; | 1819 | s_win.clockdiv = 0; |
1819 | break; | 1820 | break; |
1820 | case CC_OV6630: | 1821 | case CC_OV6630: |
1821 | s_win.clockdiv = 0; | 1822 | s_win.clockdiv = 0; |
1822 | break; | 1823 | break; |
1823 | case CC_OV76BE: | 1824 | case CC_OV76BE: |
1824 | case CC_OV7610: | 1825 | case CC_OV7610: |
1825 | case CC_OV7620: | 1826 | case CC_OV7620: |
1826 | s_win.clockdiv = 0; | 1827 | s_win.clockdiv = 0; |
1827 | break; | 1828 | break; |
1828 | default: | 1829 | default: |
1829 | s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; | 1830 | s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; |
1830 | } | 1831 | } |
1831 | 1832 | ||
1832 | /* We have to scale win.x and win.y offsets */ | 1833 | /* We have to scale win.x and win.y offsets */ |
1833 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | 1834 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) |
1834 | || (cam->vpp_flag & VPP_UPSCALE) ) { | 1835 | || (cam->vpp_flag & VPP_UPSCALE) ) { |
1835 | ax = SC(win.x)/fw; | 1836 | ax = SC(win.x)/fw; |
1836 | ay = SC(win.y)/fh; | 1837 | ay = SC(win.y)/fh; |
1837 | } else { | 1838 | } else { |
1838 | ax = win.x; | 1839 | ax = win.x; |
1839 | ay = win.y; | 1840 | ay = win.y; |
1840 | } | 1841 | } |
1841 | 1842 | ||
1842 | if ((ax + cw) > cam->maxwidth) | 1843 | if ((ax + cw) > cam->maxwidth) |
1843 | ax = cam->maxwidth - cw; | 1844 | ax = cam->maxwidth - cw; |
1844 | 1845 | ||
1845 | if ((ay + ch) > cam->maxheight) | 1846 | if ((ay + ch) > cam->maxheight) |
1846 | ay = cam->maxheight - ch; | 1847 | ay = cam->maxheight - ch; |
1847 | 1848 | ||
1848 | /* Adjust win.x, win.y */ | 1849 | /* Adjust win.x, win.y */ |
1849 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | 1850 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) |
1850 | || (cam->vpp_flag & VPP_UPSCALE) ) { | 1851 | || (cam->vpp_flag & VPP_UPSCALE) ) { |
1851 | win.x = UNSC(ax*fw); | 1852 | win.x = UNSC(ax*fw); |
1852 | win.y = UNSC(ay*fh); | 1853 | win.y = UNSC(ay*fh); |
1853 | } else { | 1854 | } else { |
1854 | win.x = ax; | 1855 | win.x = ax; |
1855 | win.y = ay; | 1856 | win.y = ay; |
1856 | } | 1857 | } |
1857 | 1858 | ||
1858 | /* Offsets used by the chip */ | 1859 | /* Offsets used by the chip */ |
1859 | x = ax + s_win.x; | 1860 | x = ax + s_win.x; |
1860 | y = ay + s_win.y; | 1861 | y = ay + s_win.y; |
1861 | 1862 | ||
1862 | /* Go ! */ | 1863 | /* Go ! */ |
1863 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) | 1864 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) |
1864 | goto error; | 1865 | goto error; |
1865 | 1866 | ||
1866 | err += w9968cf_write_reg(cam, scx + x, 0x10); | 1867 | err += w9968cf_write_reg(cam, scx + x, 0x10); |
1867 | err += w9968cf_write_reg(cam, scy + y, 0x11); | 1868 | err += w9968cf_write_reg(cam, scy + y, 0x11); |
1868 | err += w9968cf_write_reg(cam, scx + x + cw, 0x12); | 1869 | err += w9968cf_write_reg(cam, scx + x + cw, 0x12); |
1869 | err += w9968cf_write_reg(cam, scy + y + ch, 0x13); | 1870 | err += w9968cf_write_reg(cam, scy + y + ch, 0x13); |
1870 | err += w9968cf_write_reg(cam, w, 0x14); | 1871 | err += w9968cf_write_reg(cam, w, 0x14); |
1871 | err += w9968cf_write_reg(cam, h, 0x15); | 1872 | err += w9968cf_write_reg(cam, h, 0x15); |
1872 | 1873 | ||
1873 | /* JPEG width & height */ | 1874 | /* JPEG width & height */ |
1874 | err += w9968cf_write_reg(cam, w, 0x30); | 1875 | err += w9968cf_write_reg(cam, w, 0x30); |
1875 | err += w9968cf_write_reg(cam, h, 0x31); | 1876 | err += w9968cf_write_reg(cam, h, 0x31); |
1876 | 1877 | ||
1877 | /* Y & UV frame buffer strides (in WORD) */ | 1878 | /* Y & UV frame buffer strides (in WORD) */ |
1878 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | 1879 | if (cam->vpp_flag & VPP_DECOMPRESSION) { |
1879 | err += w9968cf_write_reg(cam, w/2, 0x2c); | 1880 | err += w9968cf_write_reg(cam, w/2, 0x2c); |
1880 | err += w9968cf_write_reg(cam, w/4, 0x2d); | 1881 | err += w9968cf_write_reg(cam, w/4, 0x2d); |
1881 | } else | 1882 | } else |
1882 | err += w9968cf_write_reg(cam, w, 0x2c); | 1883 | err += w9968cf_write_reg(cam, w, 0x2c); |
1883 | 1884 | ||
1884 | if (err) | 1885 | if (err) |
1885 | goto error; | 1886 | goto error; |
1886 | 1887 | ||
1887 | /* If all went well, update the device data structure */ | 1888 | /* If all went well, update the device data structure */ |
1888 | memcpy(&cam->window, &win, sizeof(win)); | 1889 | memcpy(&cam->window, &win, sizeof(win)); |
1889 | cam->hw_width = w; | 1890 | cam->hw_width = w; |
1890 | cam->hw_height = h; | 1891 | cam->hw_height = h; |
1891 | 1892 | ||
1892 | /* Settings changed, so we clear the frame buffers */ | 1893 | /* Settings changed, so we clear the frame buffers */ |
1893 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | 1894 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); |
1894 | 1895 | ||
1895 | DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", | 1896 | DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", |
1896 | win.width, win.height, win.x, win.y) | 1897 | win.width, win.height, win.x, win.y) |
1897 | 1898 | ||
1898 | PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " | 1899 | PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " |
1899 | "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", | 1900 | "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", |
1900 | x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, | 1901 | x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, |
1901 | win.width, win.height) | 1902 | win.width, win.height) |
1902 | 1903 | ||
1903 | return 0; | 1904 | return 0; |
1904 | 1905 | ||
1905 | error: | 1906 | error: |
1906 | DBG(1, "Failed to change the capture area size") | 1907 | DBG(1, "Failed to change the capture area size") |
1907 | return err; | 1908 | return err; |
1908 | } | 1909 | } |
1909 | 1910 | ||
1910 | 1911 | ||
1911 | /*-------------------------------------------------------------------------- | 1912 | /*-------------------------------------------------------------------------- |
1912 | Adjust the asked values for window width and height. | 1913 | Adjust the asked values for window width and height. |
1913 | Return 0 on success, -1 otherwise. | 1914 | Return 0 on success, -1 otherwise. |
1914 | --------------------------------------------------------------------------*/ | 1915 | --------------------------------------------------------------------------*/ |
1915 | static int | 1916 | static int |
1916 | w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) | 1917 | w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) |
1917 | { | 1918 | { |
1918 | u16 maxw, maxh; | 1919 | u16 maxw, maxh; |
1919 | 1920 | ||
1920 | if ((*width < cam->minwidth) || (*height < cam->minheight)) | 1921 | if ((*width < cam->minwidth) || (*height < cam->minheight)) |
1921 | return -ERANGE; | 1922 | return -ERANGE; |
1922 | 1923 | ||
1923 | maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | 1924 | maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && |
1924 | w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | 1925 | w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) |
1925 | : cam->maxwidth; | 1926 | : cam->maxwidth; |
1926 | maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | 1927 | maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && |
1927 | w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | 1928 | w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) |
1928 | : cam->maxheight; | 1929 | : cam->maxheight; |
1929 | 1930 | ||
1930 | if (*width > maxw) | 1931 | if (*width > maxw) |
1931 | *width = maxw; | 1932 | *width = maxw; |
1932 | if (*height > maxh) | 1933 | if (*height > maxh) |
1933 | *height = maxh; | 1934 | *height = maxh; |
1934 | 1935 | ||
1935 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | 1936 | if (cam->vpp_flag & VPP_DECOMPRESSION) { |
1936 | *width &= ~15L; /* multiple of 16 */ | 1937 | *width &= ~15L; /* multiple of 16 */ |
1937 | *height &= ~15L; | 1938 | *height &= ~15L; |
1938 | } | 1939 | } |
1939 | 1940 | ||
1940 | PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) | 1941 | PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) |
1941 | 1942 | ||
1942 | return 0; | 1943 | return 0; |
1943 | } | 1944 | } |
1944 | 1945 | ||
1945 | 1946 | ||
1946 | /*-------------------------------------------------------------------------- | 1947 | /*-------------------------------------------------------------------------- |
1947 | Initialize the FIFO list of requested frames. | 1948 | Initialize the FIFO list of requested frames. |
1948 | --------------------------------------------------------------------------*/ | 1949 | --------------------------------------------------------------------------*/ |
1949 | static void w9968cf_init_framelist(struct w9968cf_device* cam) | 1950 | static void w9968cf_init_framelist(struct w9968cf_device* cam) |
1950 | { | 1951 | { |
1951 | u8 i; | 1952 | u8 i; |
1952 | 1953 | ||
1953 | for (i = 0; i < cam->nbuffers; i++) { | 1954 | for (i = 0; i < cam->nbuffers; i++) { |
1954 | cam->requested_frame[i] = NULL; | 1955 | cam->requested_frame[i] = NULL; |
1955 | cam->frame[i].queued = 0; | 1956 | cam->frame[i].queued = 0; |
1956 | cam->frame[i].status = F_UNUSED; | 1957 | cam->frame[i].status = F_UNUSED; |
1957 | } | 1958 | } |
1958 | } | 1959 | } |
1959 | 1960 | ||
1960 | 1961 | ||
1961 | /*-------------------------------------------------------------------------- | 1962 | /*-------------------------------------------------------------------------- |
1962 | Add a frame in the FIFO list of requested frames. | 1963 | Add a frame in the FIFO list of requested frames. |
1963 | This function is called in process context. | 1964 | This function is called in process context. |
1964 | --------------------------------------------------------------------------*/ | 1965 | --------------------------------------------------------------------------*/ |
1965 | static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) | 1966 | static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) |
1966 | { | 1967 | { |
1967 | u8 f; | 1968 | u8 f; |
1968 | unsigned long lock_flags; | 1969 | unsigned long lock_flags; |
1969 | 1970 | ||
1970 | spin_lock_irqsave(&cam->flist_lock, lock_flags); | 1971 | spin_lock_irqsave(&cam->flist_lock, lock_flags); |
1971 | 1972 | ||
1972 | for (f=0; cam->requested_frame[f] != NULL; f++); | 1973 | for (f=0; cam->requested_frame[f] != NULL; f++); |
1973 | cam->requested_frame[f] = &cam->frame[f_num]; | 1974 | cam->requested_frame[f] = &cam->frame[f_num]; |
1974 | cam->frame[f_num].queued = 1; | 1975 | cam->frame[f_num].queued = 1; |
1975 | cam->frame[f_num].status = F_UNUSED; /* clear the status */ | 1976 | cam->frame[f_num].status = F_UNUSED; /* clear the status */ |
1976 | 1977 | ||
1977 | spin_unlock_irqrestore(&cam->flist_lock, lock_flags); | 1978 | spin_unlock_irqrestore(&cam->flist_lock, lock_flags); |
1978 | 1979 | ||
1979 | DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) | 1980 | DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) |
1980 | } | 1981 | } |
1981 | 1982 | ||
1982 | 1983 | ||
1983 | /*-------------------------------------------------------------------------- | 1984 | /*-------------------------------------------------------------------------- |
1984 | Read, store and remove the first pointer in the FIFO list of requested | 1985 | Read, store and remove the first pointer in the FIFO list of requested |
1985 | frames. This function is called in interrupt context. | 1986 | frames. This function is called in interrupt context. |
1986 | --------------------------------------------------------------------------*/ | 1987 | --------------------------------------------------------------------------*/ |
1987 | static void | 1988 | static void |
1988 | w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) | 1989 | w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) |
1989 | { | 1990 | { |
1990 | u8 i; | 1991 | u8 i; |
1991 | 1992 | ||
1992 | spin_lock(&cam->flist_lock); | 1993 | spin_lock(&cam->flist_lock); |
1993 | 1994 | ||
1994 | *framep = cam->requested_frame[0]; | 1995 | *framep = cam->requested_frame[0]; |
1995 | 1996 | ||
1996 | /* Shift the list of pointers */ | 1997 | /* Shift the list of pointers */ |
1997 | for (i = 0; i < cam->nbuffers-1; i++) | 1998 | for (i = 0; i < cam->nbuffers-1; i++) |
1998 | cam->requested_frame[i] = cam->requested_frame[i+1]; | 1999 | cam->requested_frame[i] = cam->requested_frame[i+1]; |
1999 | cam->requested_frame[i] = NULL; | 2000 | cam->requested_frame[i] = NULL; |
2000 | 2001 | ||
2001 | spin_unlock(&cam->flist_lock); | 2002 | spin_unlock(&cam->flist_lock); |
2002 | 2003 | ||
2003 | DBG(6,"Popped frame #%d from the list", (*framep)->number) | 2004 | DBG(6,"Popped frame #%d from the list", (*framep)->number) |
2004 | } | 2005 | } |
2005 | 2006 | ||
2006 | 2007 | ||
2007 | /*-------------------------------------------------------------------------- | 2008 | /*-------------------------------------------------------------------------- |
2008 | High-level video post-processing routine on grabbed frames. | 2009 | High-level video post-processing routine on grabbed frames. |
2009 | Return 0 on success, a negative number otherwise. | 2010 | Return 0 on success, a negative number otherwise. |
2010 | --------------------------------------------------------------------------*/ | 2011 | --------------------------------------------------------------------------*/ |
2011 | static int | 2012 | static int |
2012 | w9968cf_postprocess_frame(struct w9968cf_device* cam, | 2013 | w9968cf_postprocess_frame(struct w9968cf_device* cam, |
2013 | struct w9968cf_frame_t* fr) | 2014 | struct w9968cf_frame_t* fr) |
2014 | { | 2015 | { |
2015 | void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; | 2016 | void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; |
2016 | u16 w = cam->window.width, | 2017 | u16 w = cam->window.width, |
2017 | h = cam->window.height, | 2018 | h = cam->window.height, |
2018 | d = cam->picture.depth, | 2019 | d = cam->picture.depth, |
2019 | fmt = cam->picture.palette, | 2020 | fmt = cam->picture.palette, |
2020 | rgb = cam->force_rgb, | 2021 | rgb = cam->force_rgb, |
2021 | hw_w = cam->hw_width, | 2022 | hw_w = cam->hw_width, |
2022 | hw_h = cam->hw_height, | 2023 | hw_h = cam->hw_height, |
2023 | hw_d = cam->hw_depth; | 2024 | hw_d = cam->hw_depth; |
2024 | int err = 0; | 2025 | int err = 0; |
2025 | 2026 | ||
2026 | #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} | 2027 | #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} |
2027 | 2028 | ||
2028 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | 2029 | if (cam->vpp_flag & VPP_DECOMPRESSION) { |
2029 | memcpy(pOut, pIn, fr->length); | 2030 | memcpy(pOut, pIn, fr->length); |
2030 | _PSWAP(pIn, pOut) | 2031 | _PSWAP(pIn, pOut) |
2031 | err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); | 2032 | err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); |
2032 | PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) | 2033 | PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) |
2033 | fr->length = (hw_w*hw_h*hw_d)/8; | 2034 | fr->length = (hw_w*hw_h*hw_d)/8; |
2034 | _PSWAP(pIn, pOut) | 2035 | _PSWAP(pIn, pOut) |
2035 | if (err) { | 2036 | if (err) { |
2036 | DBG(4, "An error occurred while decoding the frame: " | 2037 | DBG(4, "An error occurred while decoding the frame: " |
2037 | "%s", symbolic(decoder_errlist, err)) | 2038 | "%s", symbolic(decoder_errlist, err)) |
2038 | return err; | 2039 | return err; |
2039 | } else | 2040 | } else |
2040 | DBG(6, "Frame decoded") | 2041 | DBG(6, "Frame decoded") |
2041 | } | 2042 | } |
2042 | 2043 | ||
2043 | if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { | 2044 | if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { |
2044 | w9968cf_vpp->swap_yuvbytes(pIn, fr->length); | 2045 | w9968cf_vpp->swap_yuvbytes(pIn, fr->length); |
2045 | DBG(6, "Original UYVY component ordering changed") | 2046 | DBG(6, "Original UYVY component ordering changed") |
2046 | } | 2047 | } |
2047 | 2048 | ||
2048 | if (cam->vpp_flag & VPP_UPSCALE) { | 2049 | if (cam->vpp_flag & VPP_UPSCALE) { |
2049 | w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); | 2050 | w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); |
2050 | fr->length = (w*h*hw_d)/8; | 2051 | fr->length = (w*h*hw_d)/8; |
2051 | _PSWAP(pIn, pOut) | 2052 | _PSWAP(pIn, pOut) |
2052 | DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", | 2053 | DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", |
2053 | hw_w, hw_h, hw_d, w, h) | 2054 | hw_w, hw_h, hw_d, w, h) |
2054 | } | 2055 | } |
2055 | 2056 | ||
2056 | if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { | 2057 | if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { |
2057 | w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); | 2058 | w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); |
2058 | fr->length = (w*h*d)/8; | 2059 | fr->length = (w*h*d)/8; |
2059 | _PSWAP(pIn, pOut) | 2060 | _PSWAP(pIn, pOut) |
2060 | DBG(6, "UYVY-16bit to %s conversion done", | 2061 | DBG(6, "UYVY-16bit to %s conversion done", |
2061 | symbolic(v4l1_plist, fmt)) | 2062 | symbolic(v4l1_plist, fmt)) |
2062 | } | 2063 | } |
2063 | 2064 | ||
2064 | if (pOut == fr->buffer) | 2065 | if (pOut == fr->buffer) |
2065 | memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); | 2066 | memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); |
2066 | 2067 | ||
2067 | return 0; | 2068 | return 0; |
2068 | } | 2069 | } |
2069 | 2070 | ||
2070 | 2071 | ||
2071 | 2072 | ||
2072 | /**************************************************************************** | 2073 | /**************************************************************************** |
2073 | * Image sensor control routines * | 2074 | * Image sensor control routines * |
2074 | ****************************************************************************/ | 2075 | ****************************************************************************/ |
2075 | 2076 | ||
2076 | static int | 2077 | static int |
2077 | w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) | 2078 | w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) |
2078 | { | 2079 | { |
2079 | struct ovcamchip_control ctl; | 2080 | struct ovcamchip_control ctl; |
2080 | int err; | 2081 | int err; |
2081 | 2082 | ||
2082 | ctl.id = cid; | 2083 | ctl.id = cid; |
2083 | ctl.value = val; | 2084 | ctl.value = val; |
2084 | 2085 | ||
2085 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); | 2086 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); |
2086 | 2087 | ||
2087 | return err; | 2088 | return err; |
2088 | } | 2089 | } |
2089 | 2090 | ||
2090 | 2091 | ||
2091 | static int | 2092 | static int |
2092 | w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) | 2093 | w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) |
2093 | { | 2094 | { |
2094 | struct ovcamchip_control ctl; | 2095 | struct ovcamchip_control ctl; |
2095 | int err; | 2096 | int err; |
2096 | 2097 | ||
2097 | ctl.id = cid; | 2098 | ctl.id = cid; |
2098 | 2099 | ||
2099 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); | 2100 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); |
2100 | if (!err) | 2101 | if (!err) |
2101 | *val = ctl.value; | 2102 | *val = ctl.value; |
2102 | 2103 | ||
2103 | return err; | 2104 | return err; |
2104 | } | 2105 | } |
2105 | 2106 | ||
2106 | 2107 | ||
2107 | static int | 2108 | static int |
2108 | w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) | 2109 | w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) |
2109 | { | 2110 | { |
2110 | int rc; | 2111 | int rc; |
2111 | 2112 | ||
2112 | rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg); | 2113 | rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg); |
2113 | /* The I2C driver returns -EPERM on non-supported controls */ | 2114 | /* The I2C driver returns -EPERM on non-supported controls */ |
2114 | return (rc < 0 && rc != -EPERM) ? rc : 0; | 2115 | return (rc < 0 && rc != -EPERM) ? rc : 0; |
2115 | } | 2116 | } |
2116 | 2117 | ||
2117 | 2118 | ||
2118 | /*-------------------------------------------------------------------------- | 2119 | /*-------------------------------------------------------------------------- |
2119 | Update some settings of the image sensor. | 2120 | Update some settings of the image sensor. |
2120 | Returns: 0 on success, a negative number otherwise. | 2121 | Returns: 0 on success, a negative number otherwise. |
2121 | --------------------------------------------------------------------------*/ | 2122 | --------------------------------------------------------------------------*/ |
2122 | static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) | 2123 | static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) |
2123 | { | 2124 | { |
2124 | int err = 0; | 2125 | int err = 0; |
2125 | 2126 | ||
2126 | /* Auto brightness */ | 2127 | /* Auto brightness */ |
2127 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, | 2128 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, |
2128 | cam->auto_brt); | 2129 | cam->auto_brt); |
2129 | if (err) | 2130 | if (err) |
2130 | return err; | 2131 | return err; |
2131 | 2132 | ||
2132 | /* Auto exposure */ | 2133 | /* Auto exposure */ |
2133 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, | 2134 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, |
2134 | cam->auto_exp); | 2135 | cam->auto_exp); |
2135 | if (err) | 2136 | if (err) |
2136 | return err; | 2137 | return err; |
2137 | 2138 | ||
2138 | /* Banding filter */ | 2139 | /* Banding filter */ |
2139 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, | 2140 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, |
2140 | cam->bandfilt); | 2141 | cam->bandfilt); |
2141 | if (err) | 2142 | if (err) |
2142 | return err; | 2143 | return err; |
2143 | 2144 | ||
2144 | /* Light frequency */ | 2145 | /* Light frequency */ |
2145 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, | 2146 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, |
2146 | cam->lightfreq); | 2147 | cam->lightfreq); |
2147 | if (err) | 2148 | if (err) |
2148 | return err; | 2149 | return err; |
2149 | 2150 | ||
2150 | /* Back light */ | 2151 | /* Back light */ |
2151 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, | 2152 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, |
2152 | cam->backlight); | 2153 | cam->backlight); |
2153 | if (err) | 2154 | if (err) |
2154 | return err; | 2155 | return err; |
2155 | 2156 | ||
2156 | /* Mirror */ | 2157 | /* Mirror */ |
2157 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, | 2158 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, |
2158 | cam->mirror); | 2159 | cam->mirror); |
2159 | if (err) | 2160 | if (err) |
2160 | return err; | 2161 | return err; |
2161 | 2162 | ||
2162 | return 0; | 2163 | return 0; |
2163 | } | 2164 | } |
2164 | 2165 | ||
2165 | 2166 | ||
2166 | /*-------------------------------------------------------------------------- | 2167 | /*-------------------------------------------------------------------------- |
2167 | Get some current picture settings from the image sensor and update the | 2168 | Get some current picture settings from the image sensor and update the |
2168 | internal 'picture' structure of the camera. | 2169 | internal 'picture' structure of the camera. |
2169 | Returns: 0 on success, a negative number otherwise. | 2170 | Returns: 0 on success, a negative number otherwise. |
2170 | --------------------------------------------------------------------------*/ | 2171 | --------------------------------------------------------------------------*/ |
2171 | static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) | 2172 | static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) |
2172 | { | 2173 | { |
2173 | int err, v; | 2174 | int err, v; |
2174 | 2175 | ||
2175 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); | 2176 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); |
2176 | if (err) | 2177 | if (err) |
2177 | return err; | 2178 | return err; |
2178 | cam->picture.contrast = v; | 2179 | cam->picture.contrast = v; |
2179 | 2180 | ||
2180 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); | 2181 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); |
2181 | if (err) | 2182 | if (err) |
2182 | return err; | 2183 | return err; |
2183 | cam->picture.brightness = v; | 2184 | cam->picture.brightness = v; |
2184 | 2185 | ||
2185 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); | 2186 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); |
2186 | if (err) | 2187 | if (err) |
2187 | return err; | 2188 | return err; |
2188 | cam->picture.colour = v; | 2189 | cam->picture.colour = v; |
2189 | 2190 | ||
2190 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); | 2191 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); |
2191 | if (err) | 2192 | if (err) |
2192 | return err; | 2193 | return err; |
2193 | cam->picture.hue = v; | 2194 | cam->picture.hue = v; |
2194 | 2195 | ||
2195 | DBG(5, "Got picture settings from the image sensor") | 2196 | DBG(5, "Got picture settings from the image sensor") |
2196 | 2197 | ||
2197 | PDBGG("Brightness, contrast, hue, colour, whiteness are " | 2198 | PDBGG("Brightness, contrast, hue, colour, whiteness are " |
2198 | "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, | 2199 | "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, |
2199 | cam->picture.hue, cam->picture.colour, cam->picture.whiteness) | 2200 | cam->picture.hue, cam->picture.colour, cam->picture.whiteness) |
2200 | 2201 | ||
2201 | return 0; | 2202 | return 0; |
2202 | } | 2203 | } |
2203 | 2204 | ||
2204 | 2205 | ||
2205 | /*-------------------------------------------------------------------------- | 2206 | /*-------------------------------------------------------------------------- |
2206 | Update picture settings of the image sensor. | 2207 | Update picture settings of the image sensor. |
2207 | Returns: 0 on success, a negative number otherwise. | 2208 | Returns: 0 on success, a negative number otherwise. |
2208 | --------------------------------------------------------------------------*/ | 2209 | --------------------------------------------------------------------------*/ |
2209 | static int | 2210 | static int |
2210 | w9968cf_sensor_update_picture(struct w9968cf_device* cam, | 2211 | w9968cf_sensor_update_picture(struct w9968cf_device* cam, |
2211 | struct video_picture pict) | 2212 | struct video_picture pict) |
2212 | { | 2213 | { |
2213 | int err = 0; | 2214 | int err = 0; |
2214 | 2215 | ||
2215 | if ((!cam->sensor_initialized) | 2216 | if ((!cam->sensor_initialized) |
2216 | || pict.contrast != cam->picture.contrast) { | 2217 | || pict.contrast != cam->picture.contrast) { |
2217 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, | 2218 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, |
2218 | pict.contrast); | 2219 | pict.contrast); |
2219 | if (err) | 2220 | if (err) |
2220 | goto fail; | 2221 | goto fail; |
2221 | DBG(4, "Contrast changed from %u to %u", | 2222 | DBG(4, "Contrast changed from %u to %u", |
2222 | cam->picture.contrast, pict.contrast) | 2223 | cam->picture.contrast, pict.contrast) |
2223 | cam->picture.contrast = pict.contrast; | 2224 | cam->picture.contrast = pict.contrast; |
2224 | } | 2225 | } |
2225 | 2226 | ||
2226 | if (((!cam->sensor_initialized) || | 2227 | if (((!cam->sensor_initialized) || |
2227 | pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { | 2228 | pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { |
2228 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, | 2229 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, |
2229 | pict.brightness); | 2230 | pict.brightness); |
2230 | if (err) | 2231 | if (err) |
2231 | goto fail; | 2232 | goto fail; |
2232 | DBG(4, "Brightness changed from %u to %u", | 2233 | DBG(4, "Brightness changed from %u to %u", |
2233 | cam->picture.brightness, pict.brightness) | 2234 | cam->picture.brightness, pict.brightness) |
2234 | cam->picture.brightness = pict.brightness; | 2235 | cam->picture.brightness = pict.brightness; |
2235 | } | 2236 | } |
2236 | 2237 | ||
2237 | if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { | 2238 | if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { |
2238 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, | 2239 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, |
2239 | pict.colour); | 2240 | pict.colour); |
2240 | if (err) | 2241 | if (err) |
2241 | goto fail; | 2242 | goto fail; |
2242 | DBG(4, "Colour changed from %u to %u", | 2243 | DBG(4, "Colour changed from %u to %u", |
2243 | cam->picture.colour, pict.colour) | 2244 | cam->picture.colour, pict.colour) |
2244 | cam->picture.colour = pict.colour; | 2245 | cam->picture.colour = pict.colour; |
2245 | } | 2246 | } |
2246 | 2247 | ||
2247 | if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { | 2248 | if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { |
2248 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, | 2249 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, |
2249 | pict.hue); | 2250 | pict.hue); |
2250 | if (err) | 2251 | if (err) |
2251 | goto fail; | 2252 | goto fail; |
2252 | DBG(4, "Hue changed from %u to %u", | 2253 | DBG(4, "Hue changed from %u to %u", |
2253 | cam->picture.hue, pict.hue) | 2254 | cam->picture.hue, pict.hue) |
2254 | cam->picture.hue = pict.hue; | 2255 | cam->picture.hue = pict.hue; |
2255 | } | 2256 | } |
2256 | 2257 | ||
2257 | return 0; | 2258 | return 0; |
2258 | 2259 | ||
2259 | fail: | 2260 | fail: |
2260 | DBG(4, "Failed to change sensor picture setting") | 2261 | DBG(4, "Failed to change sensor picture setting") |
2261 | return err; | 2262 | return err; |
2262 | } | 2263 | } |
2263 | 2264 | ||
2264 | 2265 | ||
2265 | 2266 | ||
2266 | /**************************************************************************** | 2267 | /**************************************************************************** |
2267 | * Camera configuration * | 2268 | * Camera configuration * |
2268 | ****************************************************************************/ | 2269 | ****************************************************************************/ |
2269 | 2270 | ||
2270 | /*-------------------------------------------------------------------------- | 2271 | /*-------------------------------------------------------------------------- |
2271 | This function is called when a supported image sensor is detected. | 2272 | This function is called when a supported image sensor is detected. |
2272 | Return 0 if the initialization succeeds, a negative number otherwise. | 2273 | Return 0 if the initialization succeeds, a negative number otherwise. |
2273 | --------------------------------------------------------------------------*/ | 2274 | --------------------------------------------------------------------------*/ |
2274 | static int w9968cf_sensor_init(struct w9968cf_device* cam) | 2275 | static int w9968cf_sensor_init(struct w9968cf_device* cam) |
2275 | { | 2276 | { |
2276 | int err = 0; | 2277 | int err = 0; |
2277 | 2278 | ||
2278 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, | 2279 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, |
2279 | &cam->monochrome))) | 2280 | &cam->monochrome))) |
2280 | goto error; | 2281 | goto error; |
2281 | 2282 | ||
2282 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, | 2283 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, |
2283 | &cam->sensor))) | 2284 | &cam->sensor))) |
2284 | goto error; | 2285 | goto error; |
2285 | 2286 | ||
2286 | /* NOTE: Make sure width and height are a multiple of 16 */ | 2287 | /* NOTE: Make sure width and height are a multiple of 16 */ |
2287 | switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) { | 2288 | switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) { |
2288 | case OV6xx0_SID: | 2289 | case OV6xx0_SID: |
2289 | cam->maxwidth = 352; | 2290 | cam->maxwidth = 352; |
2290 | cam->maxheight = 288; | 2291 | cam->maxheight = 288; |
2291 | cam->minwidth = 64; | 2292 | cam->minwidth = 64; |
2292 | cam->minheight = 48; | 2293 | cam->minheight = 48; |
2293 | break; | 2294 | break; |
2294 | case OV7xx0_SID: | 2295 | case OV7xx0_SID: |
2295 | cam->maxwidth = 640; | 2296 | cam->maxwidth = 640; |
2296 | cam->maxheight = 480; | 2297 | cam->maxheight = 480; |
2297 | cam->minwidth = 64; | 2298 | cam->minwidth = 64; |
2298 | cam->minheight = 48; | 2299 | cam->minheight = 48; |
2299 | break; | 2300 | break; |
2300 | default: | 2301 | default: |
2301 | DBG(1, "Not supported image sensor detected for %s", | 2302 | DBG(1, "Not supported image sensor detected for %s", |
2302 | symbolic(camlist, cam->id)) | 2303 | symbolic(camlist, cam->id)) |
2303 | return -EINVAL; | 2304 | return -EINVAL; |
2304 | } | 2305 | } |
2305 | 2306 | ||
2306 | /* These values depend on the ones in the ovxxx0.c sources */ | 2307 | /* These values depend on the ones in the ovxxx0.c sources */ |
2307 | switch (cam->sensor) { | 2308 | switch (cam->sensor) { |
2308 | case CC_OV7620: | 2309 | case CC_OV7620: |
2309 | cam->start_cropx = 287; | 2310 | cam->start_cropx = 287; |
2310 | cam->start_cropy = 35; | 2311 | cam->start_cropy = 35; |
2311 | /* Seems to work around a bug in the image sensor */ | 2312 | /* Seems to work around a bug in the image sensor */ |
2312 | cam->vs_polarity = 1; | 2313 | cam->vs_polarity = 1; |
2313 | cam->hs_polarity = 1; | 2314 | cam->hs_polarity = 1; |
2314 | break; | 2315 | break; |
2315 | default: | 2316 | default: |
2316 | cam->start_cropx = 320; | 2317 | cam->start_cropx = 320; |
2317 | cam->start_cropy = 35; | 2318 | cam->start_cropy = 35; |
2318 | cam->vs_polarity = 1; | 2319 | cam->vs_polarity = 1; |
2319 | cam->hs_polarity = 0; | 2320 | cam->hs_polarity = 0; |
2320 | } | 2321 | } |
2321 | 2322 | ||
2322 | if ((err = w9968cf_sensor_update_settings(cam))) | 2323 | if ((err = w9968cf_sensor_update_settings(cam))) |
2323 | goto error; | 2324 | goto error; |
2324 | 2325 | ||
2325 | if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) | 2326 | if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) |
2326 | goto error; | 2327 | goto error; |
2327 | 2328 | ||
2328 | cam->sensor_initialized = 1; | 2329 | cam->sensor_initialized = 1; |
2329 | 2330 | ||
2330 | DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) | 2331 | DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) |
2331 | return 0; | 2332 | return 0; |
2332 | 2333 | ||
2333 | error: | 2334 | error: |
2334 | cam->sensor_initialized = 0; | 2335 | cam->sensor_initialized = 0; |
2335 | cam->sensor = CC_UNKNOWN; | 2336 | cam->sensor = CC_UNKNOWN; |
2336 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " | 2337 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " |
2337 | "Try to detach and attach this device again", | 2338 | "Try to detach and attach this device again", |
2338 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2339 | symbolic(camlist, cam->id), cam->v4ldev->num) |
2339 | return err; | 2340 | return err; |
2340 | } | 2341 | } |
2341 | 2342 | ||
2342 | 2343 | ||
2343 | /*-------------------------------------------------------------------------- | 2344 | /*-------------------------------------------------------------------------- |
2344 | Fill some basic fields in the main device data structure. | 2345 | Fill some basic fields in the main device data structure. |
2345 | This function is called once on w9968cf_usb_probe() for each recognized | 2346 | This function is called once on w9968cf_usb_probe() for each recognized |
2346 | camera. | 2347 | camera. |
2347 | --------------------------------------------------------------------------*/ | 2348 | --------------------------------------------------------------------------*/ |
2348 | static void | 2349 | static void |
2349 | w9968cf_configure_camera(struct w9968cf_device* cam, | 2350 | w9968cf_configure_camera(struct w9968cf_device* cam, |
2350 | struct usb_device* udev, | 2351 | struct usb_device* udev, |
2351 | enum w9968cf_model_id mod_id, | 2352 | enum w9968cf_model_id mod_id, |
2352 | const unsigned short dev_nr) | 2353 | const unsigned short dev_nr) |
2353 | { | 2354 | { |
2354 | mutex_init(&cam->fileop_mutex); | 2355 | mutex_init(&cam->fileop_mutex); |
2355 | init_waitqueue_head(&cam->open); | 2356 | init_waitqueue_head(&cam->open); |
2356 | spin_lock_init(&cam->urb_lock); | 2357 | spin_lock_init(&cam->urb_lock); |
2357 | spin_lock_init(&cam->flist_lock); | 2358 | spin_lock_init(&cam->flist_lock); |
2358 | 2359 | ||
2359 | cam->users = 0; | 2360 | cam->users = 0; |
2360 | cam->disconnected = 0; | 2361 | cam->disconnected = 0; |
2361 | cam->id = mod_id; | 2362 | cam->id = mod_id; |
2362 | cam->sensor = CC_UNKNOWN; | 2363 | cam->sensor = CC_UNKNOWN; |
2363 | cam->sensor_initialized = 0; | 2364 | cam->sensor_initialized = 0; |
2364 | 2365 | ||
2365 | /* Calculate the alternate setting number (from 1 to 16) | 2366 | /* Calculate the alternate setting number (from 1 to 16) |
2366 | according to the 'packet_size' module parameter */ | 2367 | according to the 'packet_size' module parameter */ |
2367 | if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) | 2368 | if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) |
2368 | packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; | 2369 | packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; |
2369 | for (cam->altsetting = 1; | 2370 | for (cam->altsetting = 1; |
2370 | packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; | 2371 | packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; |
2371 | cam->altsetting++); | 2372 | cam->altsetting++); |
2372 | 2373 | ||
2373 | cam->max_buffers = (max_buffers[dev_nr] < 2 || | 2374 | cam->max_buffers = (max_buffers[dev_nr] < 2 || |
2374 | max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) | 2375 | max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) |
2375 | ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; | 2376 | ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; |
2376 | 2377 | ||
2377 | cam->double_buffer = (double_buffer[dev_nr] == 0 || | 2378 | cam->double_buffer = (double_buffer[dev_nr] == 0 || |
2378 | double_buffer[dev_nr] == 1) | 2379 | double_buffer[dev_nr] == 1) |
2379 | ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; | 2380 | ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; |
2380 | 2381 | ||
2381 | cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) | 2382 | cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) |
2382 | ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; | 2383 | ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; |
2383 | 2384 | ||
2384 | cam->filter_type = (filter_type[dev_nr] == 0 || | 2385 | cam->filter_type = (filter_type[dev_nr] == 0 || |
2385 | filter_type[dev_nr] == 1 || | 2386 | filter_type[dev_nr] == 1 || |
2386 | filter_type[dev_nr] == 2) | 2387 | filter_type[dev_nr] == 2) |
2387 | ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; | 2388 | ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; |
2388 | 2389 | ||
2389 | cam->capture = 1; | 2390 | cam->capture = 1; |
2390 | 2391 | ||
2391 | cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) | 2392 | cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) |
2392 | ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; | 2393 | ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; |
2393 | 2394 | ||
2394 | cam->decompression = (decompression[dev_nr] == 0 || | 2395 | cam->decompression = (decompression[dev_nr] == 0 || |
2395 | decompression[dev_nr] == 1 || | 2396 | decompression[dev_nr] == 1 || |
2396 | decompression[dev_nr] == 2) | 2397 | decompression[dev_nr] == 2) |
2397 | ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; | 2398 | ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; |
2398 | 2399 | ||
2399 | cam->upscaling = (upscaling[dev_nr] == 0 || | 2400 | cam->upscaling = (upscaling[dev_nr] == 0 || |
2400 | upscaling[dev_nr] == 1) | 2401 | upscaling[dev_nr] == 1) |
2401 | ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; | 2402 | ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; |
2402 | 2403 | ||
2403 | cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) | 2404 | cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) |
2404 | ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; | 2405 | ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; |
2405 | 2406 | ||
2406 | cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) | 2407 | cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) |
2407 | ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; | 2408 | ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; |
2408 | 2409 | ||
2409 | cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) | 2410 | cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) |
2410 | ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; | 2411 | ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; |
2411 | 2412 | ||
2412 | cam->bandfilt = (bandingfilter[dev_nr] == 0 || | 2413 | cam->bandfilt = (bandingfilter[dev_nr] == 0 || |
2413 | bandingfilter[dev_nr] == 1) | 2414 | bandingfilter[dev_nr] == 1) |
2414 | ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; | 2415 | ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; |
2415 | 2416 | ||
2416 | cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) | 2417 | cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) |
2417 | ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; | 2418 | ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; |
2418 | 2419 | ||
2419 | cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) | 2420 | cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) |
2420 | ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; | 2421 | ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; |
2421 | 2422 | ||
2422 | cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) | 2423 | cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) |
2423 | ? (u8)mirror[dev_nr] : W9968CF_MIRROR; | 2424 | ? (u8)mirror[dev_nr] : W9968CF_MIRROR; |
2424 | 2425 | ||
2425 | cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) | 2426 | cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) |
2426 | ? monochrome[dev_nr] : W9968CF_MONOCHROME; | 2427 | ? monochrome[dev_nr] : W9968CF_MONOCHROME; |
2427 | 2428 | ||
2428 | cam->picture.brightness = (u16)brightness[dev_nr]; | 2429 | cam->picture.brightness = (u16)brightness[dev_nr]; |
2429 | cam->picture.hue = (u16)hue[dev_nr]; | 2430 | cam->picture.hue = (u16)hue[dev_nr]; |
2430 | cam->picture.colour = (u16)colour[dev_nr]; | 2431 | cam->picture.colour = (u16)colour[dev_nr]; |
2431 | cam->picture.contrast = (u16)contrast[dev_nr]; | 2432 | cam->picture.contrast = (u16)contrast[dev_nr]; |
2432 | cam->picture.whiteness = (u16)whiteness[dev_nr]; | 2433 | cam->picture.whiteness = (u16)whiteness[dev_nr]; |
2433 | if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { | 2434 | if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { |
2434 | cam->picture.palette = (u16)force_palette[dev_nr]; | 2435 | cam->picture.palette = (u16)force_palette[dev_nr]; |
2435 | cam->force_palette = 1; | 2436 | cam->force_palette = 1; |
2436 | } else { | 2437 | } else { |
2437 | cam->force_palette = 0; | 2438 | cam->force_palette = 0; |
2438 | if (cam->decompression == 0) | 2439 | if (cam->decompression == 0) |
2439 | cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; | 2440 | cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; |
2440 | else if (cam->decompression == 1) | 2441 | else if (cam->decompression == 1) |
2441 | cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; | 2442 | cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; |
2442 | else | 2443 | else |
2443 | cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; | 2444 | cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; |
2444 | } | 2445 | } |
2445 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | 2446 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); |
2446 | 2447 | ||
2447 | cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) | 2448 | cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) |
2448 | ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; | 2449 | ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; |
2449 | 2450 | ||
2450 | cam->window.x = 0; | 2451 | cam->window.x = 0; |
2451 | cam->window.y = 0; | 2452 | cam->window.y = 0; |
2452 | cam->window.width = W9968CF_WIDTH; | 2453 | cam->window.width = W9968CF_WIDTH; |
2453 | cam->window.height = W9968CF_HEIGHT; | 2454 | cam->window.height = W9968CF_HEIGHT; |
2454 | cam->window.chromakey = 0; | 2455 | cam->window.chromakey = 0; |
2455 | cam->window.clipcount = 0; | 2456 | cam->window.clipcount = 0; |
2456 | cam->window.flags = 0; | 2457 | cam->window.flags = 0; |
2457 | 2458 | ||
2458 | DBG(3, "%s configured with settings #%u:", | 2459 | DBG(3, "%s configured with settings #%u:", |
2459 | symbolic(camlist, cam->id), dev_nr) | 2460 | symbolic(camlist, cam->id), dev_nr) |
2460 | 2461 | ||
2461 | DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", | 2462 | DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", |
2462 | wMaxPacketSize[cam->altsetting-1]) | 2463 | wMaxPacketSize[cam->altsetting-1]) |
2463 | 2464 | ||
2464 | DBG(3, "- Number of requested video frame buffers: %u", | 2465 | DBG(3, "- Number of requested video frame buffers: %u", |
2465 | cam->max_buffers) | 2466 | cam->max_buffers) |
2466 | 2467 | ||
2467 | if (cam->double_buffer) | 2468 | if (cam->double_buffer) |
2468 | DBG(3, "- Hardware double buffering enabled") | 2469 | DBG(3, "- Hardware double buffering enabled") |
2469 | else | 2470 | else |
2470 | DBG(3, "- Hardware double buffering disabled") | 2471 | DBG(3, "- Hardware double buffering disabled") |
2471 | 2472 | ||
2472 | if (cam->filter_type == 0) | 2473 | if (cam->filter_type == 0) |
2473 | DBG(3, "- Video filtering disabled") | 2474 | DBG(3, "- Video filtering disabled") |
2474 | else if (cam->filter_type == 1) | 2475 | else if (cam->filter_type == 1) |
2475 | DBG(3, "- Video filtering enabled: type 1-2-1") | 2476 | DBG(3, "- Video filtering enabled: type 1-2-1") |
2476 | else if (cam->filter_type == 2) | 2477 | else if (cam->filter_type == 2) |
2477 | DBG(3, "- Video filtering enabled: type 2-3-6-3-2") | 2478 | DBG(3, "- Video filtering enabled: type 2-3-6-3-2") |
2478 | 2479 | ||
2479 | if (cam->clamping) | 2480 | if (cam->clamping) |
2480 | DBG(3, "- Video data clamping (CCIR-601 format) enabled") | 2481 | DBG(3, "- Video data clamping (CCIR-601 format) enabled") |
2481 | else | 2482 | else |
2482 | DBG(3, "- Video data clamping (CCIR-601 format) disabled") | 2483 | DBG(3, "- Video data clamping (CCIR-601 format) disabled") |
2483 | 2484 | ||
2484 | if (cam->largeview) | 2485 | if (cam->largeview) |
2485 | DBG(3, "- Large view enabled") | 2486 | DBG(3, "- Large view enabled") |
2486 | else | 2487 | else |
2487 | DBG(3, "- Large view disabled") | 2488 | DBG(3, "- Large view disabled") |
2488 | 2489 | ||
2489 | if ((cam->decompression) == 0 && (!cam->force_palette)) | 2490 | if ((cam->decompression) == 0 && (!cam->force_palette)) |
2490 | DBG(3, "- Decompression disabled") | 2491 | DBG(3, "- Decompression disabled") |
2491 | else if ((cam->decompression) == 1 && (!cam->force_palette)) | 2492 | else if ((cam->decompression) == 1 && (!cam->force_palette)) |
2492 | DBG(3, "- Decompression forced") | 2493 | DBG(3, "- Decompression forced") |
2493 | else if ((cam->decompression) == 2 && (!cam->force_palette)) | 2494 | else if ((cam->decompression) == 2 && (!cam->force_palette)) |
2494 | DBG(3, "- Decompression allowed") | 2495 | DBG(3, "- Decompression allowed") |
2495 | 2496 | ||
2496 | if (cam->upscaling) | 2497 | if (cam->upscaling) |
2497 | DBG(3, "- Software image scaling enabled") | 2498 | DBG(3, "- Software image scaling enabled") |
2498 | else | 2499 | else |
2499 | DBG(3, "- Software image scaling disabled") | 2500 | DBG(3, "- Software image scaling disabled") |
2500 | 2501 | ||
2501 | if (cam->force_palette) | 2502 | if (cam->force_palette) |
2502 | DBG(3, "- Image palette forced to %s", | 2503 | DBG(3, "- Image palette forced to %s", |
2503 | symbolic(v4l1_plist, cam->picture.palette)) | 2504 | symbolic(v4l1_plist, cam->picture.palette)) |
2504 | 2505 | ||
2505 | if (cam->force_rgb) | 2506 | if (cam->force_rgb) |
2506 | DBG(3, "- RGB component ordering will be used instead of BGR") | 2507 | DBG(3, "- RGB component ordering will be used instead of BGR") |
2507 | 2508 | ||
2508 | if (cam->auto_brt) | 2509 | if (cam->auto_brt) |
2509 | DBG(3, "- Auto brightness enabled") | 2510 | DBG(3, "- Auto brightness enabled") |
2510 | else | 2511 | else |
2511 | DBG(3, "- Auto brightness disabled") | 2512 | DBG(3, "- Auto brightness disabled") |
2512 | 2513 | ||
2513 | if (cam->auto_exp) | 2514 | if (cam->auto_exp) |
2514 | DBG(3, "- Auto exposure enabled") | 2515 | DBG(3, "- Auto exposure enabled") |
2515 | else | 2516 | else |
2516 | DBG(3, "- Auto exposure disabled") | 2517 | DBG(3, "- Auto exposure disabled") |
2517 | 2518 | ||
2518 | if (cam->backlight) | 2519 | if (cam->backlight) |
2519 | DBG(3, "- Backlight exposure algorithm enabled") | 2520 | DBG(3, "- Backlight exposure algorithm enabled") |
2520 | else | 2521 | else |
2521 | DBG(3, "- Backlight exposure algorithm disabled") | 2522 | DBG(3, "- Backlight exposure algorithm disabled") |
2522 | 2523 | ||
2523 | if (cam->mirror) | 2524 | if (cam->mirror) |
2524 | DBG(3, "- Mirror enabled") | 2525 | DBG(3, "- Mirror enabled") |
2525 | else | 2526 | else |
2526 | DBG(3, "- Mirror disabled") | 2527 | DBG(3, "- Mirror disabled") |
2527 | 2528 | ||
2528 | if (cam->bandfilt) | 2529 | if (cam->bandfilt) |
2529 | DBG(3, "- Banding filter enabled") | 2530 | DBG(3, "- Banding filter enabled") |
2530 | else | 2531 | else |
2531 | DBG(3, "- Banding filter disabled") | 2532 | DBG(3, "- Banding filter disabled") |
2532 | 2533 | ||
2533 | DBG(3, "- Power lighting frequency: %u", cam->lightfreq) | 2534 | DBG(3, "- Power lighting frequency: %u", cam->lightfreq) |
2534 | 2535 | ||
2535 | if (cam->clockdiv == -1) | 2536 | if (cam->clockdiv == -1) |
2536 | DBG(3, "- Automatic clock divisor enabled") | 2537 | DBG(3, "- Automatic clock divisor enabled") |
2537 | else | 2538 | else |
2538 | DBG(3, "- Clock divisor: %d", cam->clockdiv) | 2539 | DBG(3, "- Clock divisor: %d", cam->clockdiv) |
2539 | 2540 | ||
2540 | if (cam->monochrome) | 2541 | if (cam->monochrome) |
2541 | DBG(3, "- Image sensor used as monochrome") | 2542 | DBG(3, "- Image sensor used as monochrome") |
2542 | else | 2543 | else |
2543 | DBG(3, "- Image sensor not used as monochrome") | 2544 | DBG(3, "- Image sensor not used as monochrome") |
2544 | } | 2545 | } |
2545 | 2546 | ||
2546 | 2547 | ||
2547 | /*-------------------------------------------------------------------------- | 2548 | /*-------------------------------------------------------------------------- |
2548 | If the video post-processing module is not loaded, some parameters | 2549 | If the video post-processing module is not loaded, some parameters |
2549 | must be overridden. | 2550 | must be overridden. |
2550 | --------------------------------------------------------------------------*/ | 2551 | --------------------------------------------------------------------------*/ |
2551 | static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | 2552 | static void w9968cf_adjust_configuration(struct w9968cf_device* cam) |
2552 | { | 2553 | { |
2553 | if (!w9968cf_vpp) { | 2554 | if (!w9968cf_vpp) { |
2554 | if (cam->decompression == 1) { | 2555 | if (cam->decompression == 1) { |
2555 | cam->decompression = 2; | 2556 | cam->decompression = 2; |
2556 | DBG(2, "Video post-processing module not found: " | 2557 | DBG(2, "Video post-processing module not found: " |
2557 | "'decompression' parameter forced to 2") | 2558 | "'decompression' parameter forced to 2") |
2558 | } | 2559 | } |
2559 | if (cam->upscaling) { | 2560 | if (cam->upscaling) { |
2560 | cam->upscaling = 0; | 2561 | cam->upscaling = 0; |
2561 | DBG(2, "Video post-processing module not found: " | 2562 | DBG(2, "Video post-processing module not found: " |
2562 | "'upscaling' parameter forced to 0") | 2563 | "'upscaling' parameter forced to 0") |
2563 | } | 2564 | } |
2564 | if (cam->picture.palette != VIDEO_PALETTE_UYVY) { | 2565 | if (cam->picture.palette != VIDEO_PALETTE_UYVY) { |
2565 | cam->force_palette = 0; | 2566 | cam->force_palette = 0; |
2566 | DBG(2, "Video post-processing module not found: " | 2567 | DBG(2, "Video post-processing module not found: " |
2567 | "'force_palette' parameter forced to 0") | 2568 | "'force_palette' parameter forced to 0") |
2568 | } | 2569 | } |
2569 | cam->picture.palette = VIDEO_PALETTE_UYVY; | 2570 | cam->picture.palette = VIDEO_PALETTE_UYVY; |
2570 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | 2571 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); |
2571 | } | 2572 | } |
2572 | } | 2573 | } |
2573 | 2574 | ||
2574 | 2575 | ||
2575 | /*-------------------------------------------------------------------------- | 2576 | /*-------------------------------------------------------------------------- |
2576 | Release the resources used by the driver. | 2577 | Release the resources used by the driver. |
2577 | This function is called on disconnect | 2578 | This function is called on disconnect |
2578 | (or on close if deallocation has been deferred) | 2579 | (or on close if deallocation has been deferred) |
2579 | --------------------------------------------------------------------------*/ | 2580 | --------------------------------------------------------------------------*/ |
2580 | static void w9968cf_release_resources(struct w9968cf_device* cam) | 2581 | static void w9968cf_release_resources(struct w9968cf_device* cam) |
2581 | { | 2582 | { |
2582 | mutex_lock(&w9968cf_devlist_mutex); | 2583 | mutex_lock(&w9968cf_devlist_mutex); |
2583 | 2584 | ||
2584 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num) | 2585 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num) |
2585 | 2586 | ||
2586 | video_unregister_device(cam->v4ldev); | 2587 | video_unregister_device(cam->v4ldev); |
2587 | list_del(&cam->v4llist); | 2588 | list_del(&cam->v4llist); |
2588 | i2c_del_adapter(&cam->i2c_adapter); | 2589 | i2c_del_adapter(&cam->i2c_adapter); |
2589 | w9968cf_deallocate_memory(cam); | 2590 | w9968cf_deallocate_memory(cam); |
2590 | kfree(cam->control_buffer); | 2591 | kfree(cam->control_buffer); |
2591 | kfree(cam->data_buffer); | 2592 | kfree(cam->data_buffer); |
2592 | v4l2_device_unregister(&cam->v4l2_dev); | 2593 | v4l2_device_unregister(&cam->v4l2_dev); |
2593 | 2594 | ||
2594 | mutex_unlock(&w9968cf_devlist_mutex); | 2595 | mutex_unlock(&w9968cf_devlist_mutex); |
2595 | } | 2596 | } |
2596 | 2597 | ||
2597 | 2598 | ||
2598 | 2599 | ||
2599 | /**************************************************************************** | 2600 | /**************************************************************************** |
2600 | * Video4Linux interface * | 2601 | * Video4Linux interface * |
2601 | ****************************************************************************/ | 2602 | ****************************************************************************/ |
2602 | 2603 | ||
2603 | static int w9968cf_open(struct file *filp) | 2604 | static int w9968cf_open(struct file *filp) |
2604 | { | 2605 | { |
2605 | struct w9968cf_device* cam; | 2606 | struct w9968cf_device* cam; |
2606 | int err; | 2607 | int err; |
2607 | 2608 | ||
2608 | /* This the only safe way to prevent race conditions with disconnect */ | 2609 | /* This the only safe way to prevent race conditions with disconnect */ |
2609 | if (!down_read_trylock(&w9968cf_disconnect)) | 2610 | if (!down_read_trylock(&w9968cf_disconnect)) |
2610 | return -EAGAIN; | 2611 | return -EAGAIN; |
2611 | 2612 | ||
2612 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2613 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2613 | 2614 | ||
2614 | mutex_lock(&cam->dev_mutex); | 2615 | mutex_lock(&cam->dev_mutex); |
2615 | 2616 | ||
2616 | if (cam->sensor == CC_UNKNOWN) { | 2617 | if (cam->sensor == CC_UNKNOWN) { |
2617 | DBG(2, "No supported image sensor has been detected by the " | 2618 | DBG(2, "No supported image sensor has been detected by the " |
2618 | "'ovcamchip' module for the %s (/dev/video%d). Make " | 2619 | "'ovcamchip' module for the %s (/dev/video%d). Make " |
2619 | "sure it is loaded *before* (re)connecting the camera.", | 2620 | "sure it is loaded *before* (re)connecting the camera.", |
2620 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2621 | symbolic(camlist, cam->id), cam->v4ldev->num) |
2621 | mutex_unlock(&cam->dev_mutex); | 2622 | mutex_unlock(&cam->dev_mutex); |
2622 | up_read(&w9968cf_disconnect); | 2623 | up_read(&w9968cf_disconnect); |
2623 | return -ENODEV; | 2624 | return -ENODEV; |
2624 | } | 2625 | } |
2625 | 2626 | ||
2626 | if (cam->users) { | 2627 | if (cam->users) { |
2627 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | 2628 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", |
2628 | symbolic(camlist, cam->id), cam->v4ldev->num, cam->command) | 2629 | symbolic(camlist, cam->id), cam->v4ldev->num, cam->command) |
2629 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | 2630 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { |
2630 | mutex_unlock(&cam->dev_mutex); | 2631 | mutex_unlock(&cam->dev_mutex); |
2631 | up_read(&w9968cf_disconnect); | 2632 | up_read(&w9968cf_disconnect); |
2632 | return -EWOULDBLOCK; | 2633 | return -EWOULDBLOCK; |
2633 | } | 2634 | } |
2634 | mutex_unlock(&cam->dev_mutex); | 2635 | mutex_unlock(&cam->dev_mutex); |
2635 | err = wait_event_interruptible_exclusive(cam->open, | 2636 | err = wait_event_interruptible_exclusive(cam->open, |
2636 | cam->disconnected || | 2637 | cam->disconnected || |
2637 | !cam->users); | 2638 | !cam->users); |
2638 | if (err) { | 2639 | if (err) { |
2639 | up_read(&w9968cf_disconnect); | 2640 | up_read(&w9968cf_disconnect); |
2640 | return err; | 2641 | return err; |
2641 | } | 2642 | } |
2642 | if (cam->disconnected) { | 2643 | if (cam->disconnected) { |
2643 | up_read(&w9968cf_disconnect); | 2644 | up_read(&w9968cf_disconnect); |
2644 | return -ENODEV; | 2645 | return -ENODEV; |
2645 | } | 2646 | } |
2646 | mutex_lock(&cam->dev_mutex); | 2647 | mutex_lock(&cam->dev_mutex); |
2647 | } | 2648 | } |
2648 | 2649 | ||
2649 | DBG(5, "Opening '%s', /dev/video%d ...", | 2650 | DBG(5, "Opening '%s', /dev/video%d ...", |
2650 | symbolic(camlist, cam->id), cam->v4ldev->num) | 2651 | symbolic(camlist, cam->id), cam->v4ldev->num) |
2651 | 2652 | ||
2652 | cam->streaming = 0; | 2653 | cam->streaming = 0; |
2653 | cam->misconfigured = 0; | 2654 | cam->misconfigured = 0; |
2654 | 2655 | ||
2655 | w9968cf_adjust_configuration(cam); | 2656 | w9968cf_adjust_configuration(cam); |
2656 | 2657 | ||
2657 | if ((err = w9968cf_allocate_memory(cam))) | 2658 | if ((err = w9968cf_allocate_memory(cam))) |
2658 | goto deallocate_memory; | 2659 | goto deallocate_memory; |
2659 | 2660 | ||
2660 | if ((err = w9968cf_init_chip(cam))) | 2661 | if ((err = w9968cf_init_chip(cam))) |
2661 | goto deallocate_memory; | 2662 | goto deallocate_memory; |
2662 | 2663 | ||
2663 | if ((err = w9968cf_start_transfer(cam))) | 2664 | if ((err = w9968cf_start_transfer(cam))) |
2664 | goto deallocate_memory; | 2665 | goto deallocate_memory; |
2665 | 2666 | ||
2666 | filp->private_data = cam; | 2667 | filp->private_data = cam; |
2667 | 2668 | ||
2668 | cam->users++; | 2669 | cam->users++; |
2669 | strcpy(cam->command, current->comm); | 2670 | strcpy(cam->command, current->comm); |
2670 | 2671 | ||
2671 | init_waitqueue_head(&cam->wait_queue); | 2672 | init_waitqueue_head(&cam->wait_queue); |
2672 | 2673 | ||
2673 | DBG(5, "Video device is open") | 2674 | DBG(5, "Video device is open") |
2674 | 2675 | ||
2675 | mutex_unlock(&cam->dev_mutex); | 2676 | mutex_unlock(&cam->dev_mutex); |
2676 | up_read(&w9968cf_disconnect); | 2677 | up_read(&w9968cf_disconnect); |
2677 | 2678 | ||
2678 | return 0; | 2679 | return 0; |
2679 | 2680 | ||
2680 | deallocate_memory: | 2681 | deallocate_memory: |
2681 | w9968cf_deallocate_memory(cam); | 2682 | w9968cf_deallocate_memory(cam); |
2682 | DBG(2, "Failed to open the video device") | 2683 | DBG(2, "Failed to open the video device") |
2683 | mutex_unlock(&cam->dev_mutex); | 2684 | mutex_unlock(&cam->dev_mutex); |
2684 | up_read(&w9968cf_disconnect); | 2685 | up_read(&w9968cf_disconnect); |
2685 | return err; | 2686 | return err; |
2686 | } | 2687 | } |
2687 | 2688 | ||
2688 | 2689 | ||
2689 | static int w9968cf_release(struct file *filp) | 2690 | static int w9968cf_release(struct file *filp) |
2690 | { | 2691 | { |
2691 | struct w9968cf_device* cam; | 2692 | struct w9968cf_device* cam; |
2692 | 2693 | ||
2693 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2694 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2694 | 2695 | ||
2695 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | 2696 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ |
2696 | 2697 | ||
2697 | w9968cf_stop_transfer(cam); | 2698 | w9968cf_stop_transfer(cam); |
2698 | 2699 | ||
2699 | if (cam->disconnected) { | 2700 | if (cam->disconnected) { |
2700 | w9968cf_release_resources(cam); | 2701 | w9968cf_release_resources(cam); |
2701 | mutex_unlock(&cam->dev_mutex); | 2702 | mutex_unlock(&cam->dev_mutex); |
2702 | kfree(cam); | 2703 | kfree(cam); |
2703 | return 0; | 2704 | return 0; |
2704 | } | 2705 | } |
2705 | 2706 | ||
2706 | cam->users--; | 2707 | cam->users--; |
2707 | w9968cf_deallocate_memory(cam); | 2708 | w9968cf_deallocate_memory(cam); |
2708 | wake_up_interruptible_nr(&cam->open, 1); | 2709 | wake_up_interruptible_nr(&cam->open, 1); |
2709 | 2710 | ||
2710 | DBG(5, "Video device closed") | 2711 | DBG(5, "Video device closed") |
2711 | mutex_unlock(&cam->dev_mutex); | 2712 | mutex_unlock(&cam->dev_mutex); |
2712 | return 0; | 2713 | return 0; |
2713 | } | 2714 | } |
2714 | 2715 | ||
2715 | 2716 | ||
2716 | static ssize_t | 2717 | static ssize_t |
2717 | w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | 2718 | w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) |
2718 | { | 2719 | { |
2719 | struct w9968cf_device* cam; | 2720 | struct w9968cf_device* cam; |
2720 | struct w9968cf_frame_t* fr; | 2721 | struct w9968cf_frame_t* fr; |
2721 | int err = 0; | 2722 | int err = 0; |
2722 | 2723 | ||
2723 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2724 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2724 | 2725 | ||
2725 | if (filp->f_flags & O_NONBLOCK) | 2726 | if (filp->f_flags & O_NONBLOCK) |
2726 | return -EWOULDBLOCK; | 2727 | return -EWOULDBLOCK; |
2727 | 2728 | ||
2728 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | 2729 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2729 | return -ERESTARTSYS; | 2730 | return -ERESTARTSYS; |
2730 | 2731 | ||
2731 | if (cam->disconnected) { | 2732 | if (cam->disconnected) { |
2732 | DBG(2, "Device not present") | 2733 | DBG(2, "Device not present") |
2733 | mutex_unlock(&cam->fileop_mutex); | 2734 | mutex_unlock(&cam->fileop_mutex); |
2734 | return -ENODEV; | 2735 | return -ENODEV; |
2735 | } | 2736 | } |
2736 | 2737 | ||
2737 | if (cam->misconfigured) { | 2738 | if (cam->misconfigured) { |
2738 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2739 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2739 | mutex_unlock(&cam->fileop_mutex); | 2740 | mutex_unlock(&cam->fileop_mutex); |
2740 | return -EIO; | 2741 | return -EIO; |
2741 | } | 2742 | } |
2742 | 2743 | ||
2743 | if (!cam->frame[0].queued) | 2744 | if (!cam->frame[0].queued) |
2744 | w9968cf_push_frame(cam, 0); | 2745 | w9968cf_push_frame(cam, 0); |
2745 | 2746 | ||
2746 | if (!cam->frame[1].queued) | 2747 | if (!cam->frame[1].queued) |
2747 | w9968cf_push_frame(cam, 1); | 2748 | w9968cf_push_frame(cam, 1); |
2748 | 2749 | ||
2749 | err = wait_event_interruptible(cam->wait_queue, | 2750 | err = wait_event_interruptible(cam->wait_queue, |
2750 | cam->frame[0].status == F_READY || | 2751 | cam->frame[0].status == F_READY || |
2751 | cam->frame[1].status == F_READY || | 2752 | cam->frame[1].status == F_READY || |
2752 | cam->disconnected); | 2753 | cam->disconnected); |
2753 | if (err) { | 2754 | if (err) { |
2754 | mutex_unlock(&cam->fileop_mutex); | 2755 | mutex_unlock(&cam->fileop_mutex); |
2755 | return err; | 2756 | return err; |
2756 | } | 2757 | } |
2757 | if (cam->disconnected) { | 2758 | if (cam->disconnected) { |
2758 | mutex_unlock(&cam->fileop_mutex); | 2759 | mutex_unlock(&cam->fileop_mutex); |
2759 | return -ENODEV; | 2760 | return -ENODEV; |
2760 | } | 2761 | } |
2761 | 2762 | ||
2762 | fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; | 2763 | fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; |
2763 | 2764 | ||
2764 | if (w9968cf_vpp) | 2765 | if (w9968cf_vpp) |
2765 | w9968cf_postprocess_frame(cam, fr); | 2766 | w9968cf_postprocess_frame(cam, fr); |
2766 | 2767 | ||
2767 | if (count > fr->length) | 2768 | if (count > fr->length) |
2768 | count = fr->length; | 2769 | count = fr->length; |
2769 | 2770 | ||
2770 | if (copy_to_user(buf, fr->buffer, count)) { | 2771 | if (copy_to_user(buf, fr->buffer, count)) { |
2771 | fr->status = F_UNUSED; | 2772 | fr->status = F_UNUSED; |
2772 | mutex_unlock(&cam->fileop_mutex); | 2773 | mutex_unlock(&cam->fileop_mutex); |
2773 | return -EFAULT; | 2774 | return -EFAULT; |
2774 | } | 2775 | } |
2775 | *f_pos += count; | 2776 | *f_pos += count; |
2776 | 2777 | ||
2777 | fr->status = F_UNUSED; | 2778 | fr->status = F_UNUSED; |
2778 | 2779 | ||
2779 | DBG(5, "%zu bytes read", count) | 2780 | DBG(5, "%zu bytes read", count) |
2780 | 2781 | ||
2781 | mutex_unlock(&cam->fileop_mutex); | 2782 | mutex_unlock(&cam->fileop_mutex); |
2782 | return count; | 2783 | return count; |
2783 | } | 2784 | } |
2784 | 2785 | ||
2785 | 2786 | ||
2786 | static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) | 2787 | static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) |
2787 | { | 2788 | { |
2788 | struct w9968cf_device* cam = (struct w9968cf_device*) | 2789 | struct w9968cf_device* cam = (struct w9968cf_device*) |
2789 | video_get_drvdata(video_devdata(filp)); | 2790 | video_get_drvdata(video_devdata(filp)); |
2790 | unsigned long vsize = vma->vm_end - vma->vm_start, | 2791 | unsigned long vsize = vma->vm_end - vma->vm_start, |
2791 | psize = cam->nbuffers * cam->frame[0].size, | 2792 | psize = cam->nbuffers * cam->frame[0].size, |
2792 | start = vma->vm_start, | 2793 | start = vma->vm_start, |
2793 | pos = (unsigned long)cam->frame[0].buffer, | 2794 | pos = (unsigned long)cam->frame[0].buffer, |
2794 | page; | 2795 | page; |
2795 | 2796 | ||
2796 | if (cam->disconnected) { | 2797 | if (cam->disconnected) { |
2797 | DBG(2, "Device not present") | 2798 | DBG(2, "Device not present") |
2798 | return -ENODEV; | 2799 | return -ENODEV; |
2799 | } | 2800 | } |
2800 | 2801 | ||
2801 | if (cam->misconfigured) { | 2802 | if (cam->misconfigured) { |
2802 | DBG(2, "The camera is misconfigured. Close and open it again") | 2803 | DBG(2, "The camera is misconfigured. Close and open it again") |
2803 | return -EIO; | 2804 | return -EIO; |
2804 | } | 2805 | } |
2805 | 2806 | ||
2806 | PDBGG("mmapping %lu bytes...", vsize) | 2807 | PDBGG("mmapping %lu bytes...", vsize) |
2807 | 2808 | ||
2808 | if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) | 2809 | if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) |
2809 | return -EINVAL; | 2810 | return -EINVAL; |
2810 | 2811 | ||
2811 | while (vsize > 0) { | 2812 | while (vsize > 0) { |
2812 | page = vmalloc_to_pfn((void *)pos); | 2813 | page = vmalloc_to_pfn((void *)pos); |
2813 | if (remap_pfn_range(vma, start, page + vma->vm_pgoff, | 2814 | if (remap_pfn_range(vma, start, page + vma->vm_pgoff, |
2814 | PAGE_SIZE, vma->vm_page_prot)) | 2815 | PAGE_SIZE, vma->vm_page_prot)) |
2815 | return -EAGAIN; | 2816 | return -EAGAIN; |
2816 | start += PAGE_SIZE; | 2817 | start += PAGE_SIZE; |
2817 | pos += PAGE_SIZE; | 2818 | pos += PAGE_SIZE; |
2818 | vsize -= PAGE_SIZE; | 2819 | vsize -= PAGE_SIZE; |
2819 | } | 2820 | } |
2820 | 2821 | ||
2821 | DBG(5, "mmap method successfully called") | 2822 | DBG(5, "mmap method successfully called") |
2822 | return 0; | 2823 | return 0; |
2823 | } | 2824 | } |
2824 | 2825 | ||
2825 | 2826 | ||
2826 | static long | 2827 | static long |
2827 | w9968cf_ioctl(struct file *filp, | 2828 | w9968cf_ioctl(struct file *filp, |
2828 | unsigned int cmd, unsigned long arg) | 2829 | unsigned int cmd, unsigned long arg) |
2829 | { | 2830 | { |
2830 | struct w9968cf_device* cam; | 2831 | struct w9968cf_device* cam; |
2831 | long err; | 2832 | long err; |
2832 | 2833 | ||
2833 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2834 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2834 | 2835 | ||
2835 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | 2836 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2836 | return -ERESTARTSYS; | 2837 | return -ERESTARTSYS; |
2837 | 2838 | ||
2838 | if (cam->disconnected) { | 2839 | if (cam->disconnected) { |
2839 | DBG(2, "Device not present") | 2840 | DBG(2, "Device not present") |
2840 | mutex_unlock(&cam->fileop_mutex); | 2841 | mutex_unlock(&cam->fileop_mutex); |
2841 | return -ENODEV; | 2842 | return -ENODEV; |
2842 | } | 2843 | } |
2843 | 2844 | ||
2844 | if (cam->misconfigured) { | 2845 | if (cam->misconfigured) { |
2845 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2846 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2846 | mutex_unlock(&cam->fileop_mutex); | 2847 | mutex_unlock(&cam->fileop_mutex); |
2847 | return -EIO; | 2848 | return -EIO; |
2848 | } | 2849 | } |
2849 | 2850 | ||
2850 | err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg); | 2851 | err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg); |
2851 | 2852 | ||
2852 | mutex_unlock(&cam->fileop_mutex); | 2853 | mutex_unlock(&cam->fileop_mutex); |
2853 | return err; | 2854 | return err; |
2854 | } | 2855 | } |
2855 | 2856 | ||
2856 | 2857 | ||
2857 | static long w9968cf_v4l_ioctl(struct file *filp, | 2858 | static long w9968cf_v4l_ioctl(struct file *filp, |
2858 | unsigned int cmd, void __user *arg) | 2859 | unsigned int cmd, void __user *arg) |
2859 | { | 2860 | { |
2860 | struct w9968cf_device* cam; | 2861 | struct w9968cf_device* cam; |
2861 | const char* v4l1_ioctls[] = { | 2862 | const char* v4l1_ioctls[] = { |
2862 | "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", | 2863 | "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", |
2863 | "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", | 2864 | "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", |
2864 | "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", | 2865 | "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", |
2865 | "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", | 2866 | "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", |
2866 | "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", | 2867 | "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", |
2867 | "GVBIFMT", "SVBIFMT" | 2868 | "GVBIFMT", "SVBIFMT" |
2868 | }; | 2869 | }; |
2869 | 2870 | ||
2870 | #define V4L1_IOCTL(cmd) \ | 2871 | #define V4L1_IOCTL(cmd) \ |
2871 | ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \ | 2872 | ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \ |
2872 | v4l1_ioctls[_IOC_NR((cmd))] : "?") | 2873 | v4l1_ioctls[_IOC_NR((cmd))] : "?") |
2873 | 2874 | ||
2874 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2875 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2875 | 2876 | ||
2876 | switch (cmd) { | 2877 | switch (cmd) { |
2877 | 2878 | ||
2878 | case VIDIOCGCAP: /* get video capability */ | 2879 | case VIDIOCGCAP: /* get video capability */ |
2879 | { | 2880 | { |
2880 | struct video_capability cap = { | 2881 | struct video_capability cap = { |
2881 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, | 2882 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, |
2882 | .channels = 1, | 2883 | .channels = 1, |
2883 | .audios = 0, | 2884 | .audios = 0, |
2884 | .minwidth = cam->minwidth, | 2885 | .minwidth = cam->minwidth, |
2885 | .minheight = cam->minheight, | 2886 | .minheight = cam->minheight, |
2886 | }; | 2887 | }; |
2887 | sprintf(cap.name, "W996[87]CF USB Camera #%d", | 2888 | sprintf(cap.name, "W996[87]CF USB Camera #%d", |
2888 | cam->v4ldev->num); | 2889 | cam->v4ldev->num); |
2889 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) | 2890 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) |
2890 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | 2891 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) |
2891 | : cam->maxwidth; | 2892 | : cam->maxwidth; |
2892 | cap.maxheight = (cam->upscaling && w9968cf_vpp) | 2893 | cap.maxheight = (cam->upscaling && w9968cf_vpp) |
2893 | ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | 2894 | ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) |
2894 | : cam->maxheight; | 2895 | : cam->maxheight; |
2895 | 2896 | ||
2896 | if (copy_to_user(arg, &cap, sizeof(cap))) | 2897 | if (copy_to_user(arg, &cap, sizeof(cap))) |
2897 | return -EFAULT; | 2898 | return -EFAULT; |
2898 | 2899 | ||
2899 | DBG(5, "VIDIOCGCAP successfully called") | 2900 | DBG(5, "VIDIOCGCAP successfully called") |
2900 | return 0; | 2901 | return 0; |
2901 | } | 2902 | } |
2902 | 2903 | ||
2903 | case VIDIOCGCHAN: /* get video channel informations */ | 2904 | case VIDIOCGCHAN: /* get video channel informations */ |
2904 | { | 2905 | { |
2905 | struct video_channel chan; | 2906 | struct video_channel chan; |
2906 | if (copy_from_user(&chan, arg, sizeof(chan))) | 2907 | if (copy_from_user(&chan, arg, sizeof(chan))) |
2907 | return -EFAULT; | 2908 | return -EFAULT; |
2908 | 2909 | ||
2909 | if (chan.channel != 0) | 2910 | if (chan.channel != 0) |
2910 | return -EINVAL; | 2911 | return -EINVAL; |
2911 | 2912 | ||
2912 | strcpy(chan.name, "Camera"); | 2913 | strcpy(chan.name, "Camera"); |
2913 | chan.tuners = 0; | 2914 | chan.tuners = 0; |
2914 | chan.flags = 0; | 2915 | chan.flags = 0; |
2915 | chan.type = VIDEO_TYPE_CAMERA; | 2916 | chan.type = VIDEO_TYPE_CAMERA; |
2916 | chan.norm = VIDEO_MODE_AUTO; | 2917 | chan.norm = VIDEO_MODE_AUTO; |
2917 | 2918 | ||
2918 | if (copy_to_user(arg, &chan, sizeof(chan))) | 2919 | if (copy_to_user(arg, &chan, sizeof(chan))) |
2919 | return -EFAULT; | 2920 | return -EFAULT; |
2920 | 2921 | ||
2921 | DBG(5, "VIDIOCGCHAN successfully called") | 2922 | DBG(5, "VIDIOCGCHAN successfully called") |
2922 | return 0; | 2923 | return 0; |
2923 | } | 2924 | } |
2924 | 2925 | ||
2925 | case VIDIOCSCHAN: /* set active channel */ | 2926 | case VIDIOCSCHAN: /* set active channel */ |
2926 | { | 2927 | { |
2927 | struct video_channel chan; | 2928 | struct video_channel chan; |
2928 | 2929 | ||
2929 | if (copy_from_user(&chan, arg, sizeof(chan))) | 2930 | if (copy_from_user(&chan, arg, sizeof(chan))) |
2930 | return -EFAULT; | 2931 | return -EFAULT; |
2931 | 2932 | ||
2932 | if (chan.channel != 0) | 2933 | if (chan.channel != 0) |
2933 | return -EINVAL; | 2934 | return -EINVAL; |
2934 | 2935 | ||
2935 | DBG(5, "VIDIOCSCHAN successfully called") | 2936 | DBG(5, "VIDIOCSCHAN successfully called") |
2936 | return 0; | 2937 | return 0; |
2937 | } | 2938 | } |
2938 | 2939 | ||
2939 | case VIDIOCGPICT: /* get image properties of the picture */ | 2940 | case VIDIOCGPICT: /* get image properties of the picture */ |
2940 | { | 2941 | { |
2941 | if (w9968cf_sensor_get_picture(cam)) | 2942 | if (w9968cf_sensor_get_picture(cam)) |
2942 | return -EIO; | 2943 | return -EIO; |
2943 | 2944 | ||
2944 | if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) | 2945 | if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) |
2945 | return -EFAULT; | 2946 | return -EFAULT; |
2946 | 2947 | ||
2947 | DBG(5, "VIDIOCGPICT successfully called") | 2948 | DBG(5, "VIDIOCGPICT successfully called") |
2948 | return 0; | 2949 | return 0; |
2949 | } | 2950 | } |
2950 | 2951 | ||
2951 | case VIDIOCSPICT: /* change picture settings */ | 2952 | case VIDIOCSPICT: /* change picture settings */ |
2952 | { | 2953 | { |
2953 | struct video_picture pict; | 2954 | struct video_picture pict; |
2954 | int err = 0; | 2955 | int err = 0; |
2955 | 2956 | ||
2956 | if (copy_from_user(&pict, arg, sizeof(pict))) | 2957 | if (copy_from_user(&pict, arg, sizeof(pict))) |
2957 | return -EFAULT; | 2958 | return -EFAULT; |
2958 | 2959 | ||
2959 | if ( (cam->force_palette || !w9968cf_vpp) | 2960 | if ( (cam->force_palette || !w9968cf_vpp) |
2960 | && pict.palette != cam->picture.palette ) { | 2961 | && pict.palette != cam->picture.palette ) { |
2961 | DBG(4, "Palette %s rejected: only %s is allowed", | 2962 | DBG(4, "Palette %s rejected: only %s is allowed", |
2962 | symbolic(v4l1_plist, pict.palette), | 2963 | symbolic(v4l1_plist, pict.palette), |
2963 | symbolic(v4l1_plist, cam->picture.palette)) | 2964 | symbolic(v4l1_plist, cam->picture.palette)) |
2964 | return -EINVAL; | 2965 | return -EINVAL; |
2965 | } | 2966 | } |
2966 | 2967 | ||
2967 | if (!w9968cf_valid_palette(pict.palette)) { | 2968 | if (!w9968cf_valid_palette(pict.palette)) { |
2968 | DBG(4, "Palette %s not supported. VIDIOCSPICT failed", | 2969 | DBG(4, "Palette %s not supported. VIDIOCSPICT failed", |
2969 | symbolic(v4l1_plist, pict.palette)) | 2970 | symbolic(v4l1_plist, pict.palette)) |
2970 | return -EINVAL; | 2971 | return -EINVAL; |
2971 | } | 2972 | } |
2972 | 2973 | ||
2973 | if (!cam->force_palette) { | 2974 | if (!cam->force_palette) { |
2974 | if (cam->decompression == 0) { | 2975 | if (cam->decompression == 0) { |
2975 | if (w9968cf_need_decompression(pict.palette)) { | 2976 | if (w9968cf_need_decompression(pict.palette)) { |
2976 | DBG(4, "Decompression disabled: palette %s is not " | 2977 | DBG(4, "Decompression disabled: palette %s is not " |
2977 | "allowed. VIDIOCSPICT failed", | 2978 | "allowed. VIDIOCSPICT failed", |
2978 | symbolic(v4l1_plist, pict.palette)) | 2979 | symbolic(v4l1_plist, pict.palette)) |
2979 | return -EINVAL; | 2980 | return -EINVAL; |
2980 | } | 2981 | } |
2981 | } else if (cam->decompression == 1) { | 2982 | } else if (cam->decompression == 1) { |
2982 | if (!w9968cf_need_decompression(pict.palette)) { | 2983 | if (!w9968cf_need_decompression(pict.palette)) { |
2983 | DBG(4, "Decompression forced: palette %s is not " | 2984 | DBG(4, "Decompression forced: palette %s is not " |
2984 | "allowed. VIDIOCSPICT failed", | 2985 | "allowed. VIDIOCSPICT failed", |
2985 | symbolic(v4l1_plist, pict.palette)) | 2986 | symbolic(v4l1_plist, pict.palette)) |
2986 | return -EINVAL; | 2987 | return -EINVAL; |
2987 | } | 2988 | } |
2988 | } | 2989 | } |
2989 | } | 2990 | } |
2990 | 2991 | ||
2991 | if (pict.depth != w9968cf_valid_depth(pict.palette)) { | 2992 | if (pict.depth != w9968cf_valid_depth(pict.palette)) { |
2992 | DBG(4, "Requested depth %u bpp is not valid for %s " | 2993 | DBG(4, "Requested depth %u bpp is not valid for %s " |
2993 | "palette: ignored and changed to %u bpp", | 2994 | "palette: ignored and changed to %u bpp", |
2994 | pict.depth, symbolic(v4l1_plist, pict.palette), | 2995 | pict.depth, symbolic(v4l1_plist, pict.palette), |
2995 | w9968cf_valid_depth(pict.palette)) | 2996 | w9968cf_valid_depth(pict.palette)) |
2996 | pict.depth = w9968cf_valid_depth(pict.palette); | 2997 | pict.depth = w9968cf_valid_depth(pict.palette); |
2997 | } | 2998 | } |
2998 | 2999 | ||
2999 | if (pict.palette != cam->picture.palette) { | 3000 | if (pict.palette != cam->picture.palette) { |
3000 | if(*cam->requested_frame | 3001 | if(*cam->requested_frame |
3001 | || cam->frame_current->queued) { | 3002 | || cam->frame_current->queued) { |
3002 | err = wait_event_interruptible | 3003 | err = wait_event_interruptible |
3003 | ( cam->wait_queue, | 3004 | ( cam->wait_queue, |
3004 | cam->disconnected || | 3005 | cam->disconnected || |
3005 | (!*cam->requested_frame && | 3006 | (!*cam->requested_frame && |
3006 | !cam->frame_current->queued) ); | 3007 | !cam->frame_current->queued) ); |
3007 | if (err) | 3008 | if (err) |
3008 | return err; | 3009 | return err; |
3009 | if (cam->disconnected) | 3010 | if (cam->disconnected) |
3010 | return -ENODEV; | 3011 | return -ENODEV; |
3011 | } | 3012 | } |
3012 | 3013 | ||
3013 | if (w9968cf_stop_transfer(cam)) | 3014 | if (w9968cf_stop_transfer(cam)) |
3014 | goto ioctl_fail; | 3015 | goto ioctl_fail; |
3015 | 3016 | ||
3016 | if (w9968cf_set_picture(cam, pict)) | 3017 | if (w9968cf_set_picture(cam, pict)) |
3017 | goto ioctl_fail; | 3018 | goto ioctl_fail; |
3018 | 3019 | ||
3019 | if (w9968cf_start_transfer(cam)) | 3020 | if (w9968cf_start_transfer(cam)) |
3020 | goto ioctl_fail; | 3021 | goto ioctl_fail; |
3021 | 3022 | ||
3022 | } else if (w9968cf_sensor_update_picture(cam, pict)) | 3023 | } else if (w9968cf_sensor_update_picture(cam, pict)) |
3023 | return -EIO; | 3024 | return -EIO; |
3024 | 3025 | ||
3025 | 3026 | ||
3026 | DBG(5, "VIDIOCSPICT successfully called") | 3027 | DBG(5, "VIDIOCSPICT successfully called") |
3027 | return 0; | 3028 | return 0; |
3028 | } | 3029 | } |
3029 | 3030 | ||
3030 | case VIDIOCSWIN: /* set capture area */ | 3031 | case VIDIOCSWIN: /* set capture area */ |
3031 | { | 3032 | { |
3032 | struct video_window win; | 3033 | struct video_window win; |
3033 | int err = 0; | 3034 | int err = 0; |
3034 | 3035 | ||
3035 | if (copy_from_user(&win, arg, sizeof(win))) | 3036 | if (copy_from_user(&win, arg, sizeof(win))) |
3036 | return -EFAULT; | 3037 | return -EFAULT; |
3037 | 3038 | ||
3038 | DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " | 3039 | DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " |
3039 | "x=%u, y=%u, %ux%u", win.clipcount, win.flags, | 3040 | "x=%u, y=%u, %ux%u", win.clipcount, win.flags, |
3040 | win.x, win.y, win.width, win.height) | 3041 | win.x, win.y, win.width, win.height) |
3041 | 3042 | ||
3042 | if (win.clipcount != 0 || win.flags != 0) | 3043 | if (win.clipcount != 0 || win.flags != 0) |
3043 | return -EINVAL; | 3044 | return -EINVAL; |
3044 | 3045 | ||
3045 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | 3046 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, |
3046 | (u16*)&win.height))) { | 3047 | (u16*)&win.height))) { |
3047 | DBG(4, "Resolution not supported (%ux%u). " | 3048 | DBG(4, "Resolution not supported (%ux%u). " |
3048 | "VIDIOCSWIN failed", win.width, win.height) | 3049 | "VIDIOCSWIN failed", win.width, win.height) |
3049 | return err; | 3050 | return err; |
3050 | } | 3051 | } |
3051 | 3052 | ||
3052 | if (win.x != cam->window.x || | 3053 | if (win.x != cam->window.x || |
3053 | win.y != cam->window.y || | 3054 | win.y != cam->window.y || |
3054 | win.width != cam->window.width || | 3055 | win.width != cam->window.width || |
3055 | win.height != cam->window.height) { | 3056 | win.height != cam->window.height) { |
3056 | if(*cam->requested_frame | 3057 | if(*cam->requested_frame |
3057 | || cam->frame_current->queued) { | 3058 | || cam->frame_current->queued) { |
3058 | err = wait_event_interruptible | 3059 | err = wait_event_interruptible |
3059 | ( cam->wait_queue, | 3060 | ( cam->wait_queue, |
3060 | cam->disconnected || | 3061 | cam->disconnected || |
3061 | (!*cam->requested_frame && | 3062 | (!*cam->requested_frame && |
3062 | !cam->frame_current->queued) ); | 3063 | !cam->frame_current->queued) ); |
3063 | if (err) | 3064 | if (err) |
3064 | return err; | 3065 | return err; |
3065 | if (cam->disconnected) | 3066 | if (cam->disconnected) |
3066 | return -ENODEV; | 3067 | return -ENODEV; |
3067 | } | 3068 | } |
3068 | 3069 | ||
3069 | if (w9968cf_stop_transfer(cam)) | 3070 | if (w9968cf_stop_transfer(cam)) |
3070 | goto ioctl_fail; | 3071 | goto ioctl_fail; |
3071 | 3072 | ||
3072 | /* This _must_ be called before set_window() */ | 3073 | /* This _must_ be called before set_window() */ |
3073 | if (w9968cf_set_picture(cam, cam->picture)) | 3074 | if (w9968cf_set_picture(cam, cam->picture)) |
3074 | goto ioctl_fail; | 3075 | goto ioctl_fail; |
3075 | 3076 | ||
3076 | if (w9968cf_set_window(cam, win)) | 3077 | if (w9968cf_set_window(cam, win)) |
3077 | goto ioctl_fail; | 3078 | goto ioctl_fail; |
3078 | 3079 | ||
3079 | if (w9968cf_start_transfer(cam)) | 3080 | if (w9968cf_start_transfer(cam)) |
3080 | goto ioctl_fail; | 3081 | goto ioctl_fail; |
3081 | } | 3082 | } |
3082 | 3083 | ||
3083 | DBG(5, "VIDIOCSWIN successfully called. ") | 3084 | DBG(5, "VIDIOCSWIN successfully called. ") |
3084 | return 0; | 3085 | return 0; |
3085 | } | 3086 | } |
3086 | 3087 | ||
3087 | case VIDIOCGWIN: /* get current window properties */ | 3088 | case VIDIOCGWIN: /* get current window properties */ |
3088 | { | 3089 | { |
3089 | if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) | 3090 | if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) |
3090 | return -EFAULT; | 3091 | return -EFAULT; |
3091 | 3092 | ||
3092 | DBG(5, "VIDIOCGWIN successfully called") | 3093 | DBG(5, "VIDIOCGWIN successfully called") |
3093 | return 0; | 3094 | return 0; |
3094 | } | 3095 | } |
3095 | 3096 | ||
3096 | case VIDIOCGMBUF: /* request for memory (mapped) buffer */ | 3097 | case VIDIOCGMBUF: /* request for memory (mapped) buffer */ |
3097 | { | 3098 | { |
3098 | struct video_mbuf mbuf; | 3099 | struct video_mbuf mbuf; |
3099 | u8 i; | 3100 | u8 i; |
3100 | 3101 | ||
3101 | mbuf.size = cam->nbuffers * cam->frame[0].size; | 3102 | mbuf.size = cam->nbuffers * cam->frame[0].size; |
3102 | mbuf.frames = cam->nbuffers; | 3103 | mbuf.frames = cam->nbuffers; |
3103 | for (i = 0; i < cam->nbuffers; i++) | 3104 | for (i = 0; i < cam->nbuffers; i++) |
3104 | mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - | 3105 | mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - |
3105 | (unsigned long)cam->frame[0].buffer; | 3106 | (unsigned long)cam->frame[0].buffer; |
3106 | 3107 | ||
3107 | if (copy_to_user(arg, &mbuf, sizeof(mbuf))) | 3108 | if (copy_to_user(arg, &mbuf, sizeof(mbuf))) |
3108 | return -EFAULT; | 3109 | return -EFAULT; |
3109 | 3110 | ||
3110 | DBG(5, "VIDIOCGMBUF successfully called") | 3111 | DBG(5, "VIDIOCGMBUF successfully called") |
3111 | return 0; | 3112 | return 0; |
3112 | } | 3113 | } |
3113 | 3114 | ||
3114 | case VIDIOCMCAPTURE: /* start the capture to a frame */ | 3115 | case VIDIOCMCAPTURE: /* start the capture to a frame */ |
3115 | { | 3116 | { |
3116 | struct video_mmap mmap; | 3117 | struct video_mmap mmap; |
3117 | struct w9968cf_frame_t* fr; | 3118 | struct w9968cf_frame_t* fr; |
3118 | int err = 0; | 3119 | int err = 0; |
3119 | 3120 | ||
3120 | if (copy_from_user(&mmap, arg, sizeof(mmap))) | 3121 | if (copy_from_user(&mmap, arg, sizeof(mmap))) |
3121 | return -EFAULT; | 3122 | return -EFAULT; |
3122 | 3123 | ||
3123 | DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", | 3124 | DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", |
3124 | mmap.frame, symbolic(v4l1_plist, mmap.format), | 3125 | mmap.frame, symbolic(v4l1_plist, mmap.format), |
3125 | mmap.width, mmap.height) | 3126 | mmap.width, mmap.height) |
3126 | 3127 | ||
3127 | if (mmap.frame >= cam->nbuffers) { | 3128 | if (mmap.frame >= cam->nbuffers) { |
3128 | DBG(4, "Invalid frame number (%u). " | 3129 | DBG(4, "Invalid frame number (%u). " |
3129 | "VIDIOCMCAPTURE failed", mmap.frame) | 3130 | "VIDIOCMCAPTURE failed", mmap.frame) |
3130 | return -EINVAL; | 3131 | return -EINVAL; |
3131 | } | 3132 | } |
3132 | 3133 | ||
3133 | if (mmap.format!=cam->picture.palette && | 3134 | if (mmap.format!=cam->picture.palette && |
3134 | (cam->force_palette || !w9968cf_vpp)) { | 3135 | (cam->force_palette || !w9968cf_vpp)) { |
3135 | DBG(4, "Palette %s rejected: only %s is allowed", | 3136 | DBG(4, "Palette %s rejected: only %s is allowed", |
3136 | symbolic(v4l1_plist, mmap.format), | 3137 | symbolic(v4l1_plist, mmap.format), |
3137 | symbolic(v4l1_plist, cam->picture.palette)) | 3138 | symbolic(v4l1_plist, cam->picture.palette)) |
3138 | return -EINVAL; | 3139 | return -EINVAL; |
3139 | } | 3140 | } |
3140 | 3141 | ||
3141 | if (!w9968cf_valid_palette(mmap.format)) { | 3142 | if (!w9968cf_valid_palette(mmap.format)) { |
3142 | DBG(4, "Palette %s not supported. " | 3143 | DBG(4, "Palette %s not supported. " |
3143 | "VIDIOCMCAPTURE failed", | 3144 | "VIDIOCMCAPTURE failed", |
3144 | symbolic(v4l1_plist, mmap.format)) | 3145 | symbolic(v4l1_plist, mmap.format)) |
3145 | return -EINVAL; | 3146 | return -EINVAL; |
3146 | } | 3147 | } |
3147 | 3148 | ||
3148 | if (!cam->force_palette) { | 3149 | if (!cam->force_palette) { |
3149 | if (cam->decompression == 0) { | 3150 | if (cam->decompression == 0) { |
3150 | if (w9968cf_need_decompression(mmap.format)) { | 3151 | if (w9968cf_need_decompression(mmap.format)) { |
3151 | DBG(4, "Decompression disabled: palette %s is not " | 3152 | DBG(4, "Decompression disabled: palette %s is not " |
3152 | "allowed. VIDIOCSPICT failed", | 3153 | "allowed. VIDIOCSPICT failed", |
3153 | symbolic(v4l1_plist, mmap.format)) | 3154 | symbolic(v4l1_plist, mmap.format)) |
3154 | return -EINVAL; | 3155 | return -EINVAL; |
3155 | } | 3156 | } |
3156 | } else if (cam->decompression == 1) { | 3157 | } else if (cam->decompression == 1) { |
3157 | if (!w9968cf_need_decompression(mmap.format)) { | 3158 | if (!w9968cf_need_decompression(mmap.format)) { |
3158 | DBG(4, "Decompression forced: palette %s is not " | 3159 | DBG(4, "Decompression forced: palette %s is not " |
3159 | "allowed. VIDIOCSPICT failed", | 3160 | "allowed. VIDIOCSPICT failed", |
3160 | symbolic(v4l1_plist, mmap.format)) | 3161 | symbolic(v4l1_plist, mmap.format)) |
3161 | return -EINVAL; | 3162 | return -EINVAL; |
3162 | } | 3163 | } |
3163 | } | 3164 | } |
3164 | } | 3165 | } |
3165 | 3166 | ||
3166 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, | 3167 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, |
3167 | (u16*)&mmap.height))) { | 3168 | (u16*)&mmap.height))) { |
3168 | DBG(4, "Resolution not supported (%dx%d). " | 3169 | DBG(4, "Resolution not supported (%dx%d). " |
3169 | "VIDIOCMCAPTURE failed", | 3170 | "VIDIOCMCAPTURE failed", |
3170 | mmap.width, mmap.height) | 3171 | mmap.width, mmap.height) |
3171 | return err; | 3172 | return err; |
3172 | } | 3173 | } |
3173 | 3174 | ||
3174 | fr = &cam->frame[mmap.frame]; | 3175 | fr = &cam->frame[mmap.frame]; |
3175 | 3176 | ||
3176 | if (mmap.width != cam->window.width || | 3177 | if (mmap.width != cam->window.width || |
3177 | mmap.height != cam->window.height || | 3178 | mmap.height != cam->window.height || |
3178 | mmap.format != cam->picture.palette) { | 3179 | mmap.format != cam->picture.palette) { |
3179 | 3180 | ||
3180 | struct video_window win; | 3181 | struct video_window win; |
3181 | struct video_picture pict; | 3182 | struct video_picture pict; |
3182 | 3183 | ||
3183 | if(*cam->requested_frame | 3184 | if(*cam->requested_frame |
3184 | || cam->frame_current->queued) { | 3185 | || cam->frame_current->queued) { |
3185 | DBG(6, "VIDIOCMCAPTURE. Change settings for " | 3186 | DBG(6, "VIDIOCMCAPTURE. Change settings for " |
3186 | "frame #%u: %dx%d, format %s. Wait...", | 3187 | "frame #%u: %dx%d, format %s. Wait...", |
3187 | mmap.frame, mmap.width, mmap.height, | 3188 | mmap.frame, mmap.width, mmap.height, |
3188 | symbolic(v4l1_plist, mmap.format)) | 3189 | symbolic(v4l1_plist, mmap.format)) |
3189 | err = wait_event_interruptible | 3190 | err = wait_event_interruptible |
3190 | ( cam->wait_queue, | 3191 | ( cam->wait_queue, |
3191 | cam->disconnected || | 3192 | cam->disconnected || |
3192 | (!*cam->requested_frame && | 3193 | (!*cam->requested_frame && |
3193 | !cam->frame_current->queued) ); | 3194 | !cam->frame_current->queued) ); |
3194 | if (err) | 3195 | if (err) |
3195 | return err; | 3196 | return err; |
3196 | if (cam->disconnected) | 3197 | if (cam->disconnected) |
3197 | return -ENODEV; | 3198 | return -ENODEV; |
3198 | } | 3199 | } |
3199 | 3200 | ||
3200 | memcpy(&win, &cam->window, sizeof(win)); | 3201 | memcpy(&win, &cam->window, sizeof(win)); |
3201 | memcpy(&pict, &cam->picture, sizeof(pict)); | 3202 | memcpy(&pict, &cam->picture, sizeof(pict)); |
3202 | win.width = mmap.width; | 3203 | win.width = mmap.width; |
3203 | win.height = mmap.height; | 3204 | win.height = mmap.height; |
3204 | pict.palette = mmap.format; | 3205 | pict.palette = mmap.format; |
3205 | 3206 | ||
3206 | if (w9968cf_stop_transfer(cam)) | 3207 | if (w9968cf_stop_transfer(cam)) |
3207 | goto ioctl_fail; | 3208 | goto ioctl_fail; |
3208 | 3209 | ||
3209 | /* This before set_window */ | 3210 | /* This before set_window */ |
3210 | if (w9968cf_set_picture(cam, pict)) | 3211 | if (w9968cf_set_picture(cam, pict)) |
3211 | goto ioctl_fail; | 3212 | goto ioctl_fail; |
3212 | 3213 | ||
3213 | if (w9968cf_set_window(cam, win)) | 3214 | if (w9968cf_set_window(cam, win)) |
3214 | goto ioctl_fail; | 3215 | goto ioctl_fail; |
3215 | 3216 | ||
3216 | if (w9968cf_start_transfer(cam)) | 3217 | if (w9968cf_start_transfer(cam)) |
3217 | goto ioctl_fail; | 3218 | goto ioctl_fail; |
3218 | 3219 | ||
3219 | } else if (fr->queued) { | 3220 | } else if (fr->queued) { |
3220 | 3221 | ||
3221 | DBG(6, "Wait until frame #%u is free", mmap.frame) | 3222 | DBG(6, "Wait until frame #%u is free", mmap.frame) |
3222 | 3223 | ||
3223 | err = wait_event_interruptible(cam->wait_queue, | 3224 | err = wait_event_interruptible(cam->wait_queue, |
3224 | cam->disconnected || | 3225 | cam->disconnected || |
3225 | (!fr->queued)); | 3226 | (!fr->queued)); |
3226 | if (err) | 3227 | if (err) |
3227 | return err; | 3228 | return err; |
3228 | if (cam->disconnected) | 3229 | if (cam->disconnected) |
3229 | return -ENODEV; | 3230 | return -ENODEV; |
3230 | } | 3231 | } |
3231 | 3232 | ||
3232 | w9968cf_push_frame(cam, mmap.frame); | 3233 | w9968cf_push_frame(cam, mmap.frame); |
3233 | DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) | 3234 | DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) |
3234 | return 0; | 3235 | return 0; |
3235 | } | 3236 | } |
3236 | 3237 | ||
3237 | case VIDIOCSYNC: /* wait until the capture of a frame is finished */ | 3238 | case VIDIOCSYNC: /* wait until the capture of a frame is finished */ |
3238 | { | 3239 | { |
3239 | unsigned int f_num; | 3240 | unsigned int f_num; |
3240 | struct w9968cf_frame_t* fr; | 3241 | struct w9968cf_frame_t* fr; |
3241 | int err = 0; | 3242 | int err = 0; |
3242 | 3243 | ||
3243 | if (copy_from_user(&f_num, arg, sizeof(f_num))) | 3244 | if (copy_from_user(&f_num, arg, sizeof(f_num))) |
3244 | return -EFAULT; | 3245 | return -EFAULT; |
3245 | 3246 | ||
3246 | if (f_num >= cam->nbuffers) { | 3247 | if (f_num >= cam->nbuffers) { |
3247 | DBG(4, "Invalid frame number (%u). " | 3248 | DBG(4, "Invalid frame number (%u). " |
3248 | "VIDIOCMCAPTURE failed", f_num) | 3249 | "VIDIOCMCAPTURE failed", f_num) |
3249 | return -EINVAL; | 3250 | return -EINVAL; |
3250 | } | 3251 | } |
3251 | 3252 | ||
3252 | DBG(6, "VIDIOCSYNC called for frame #%u", f_num) | 3253 | DBG(6, "VIDIOCSYNC called for frame #%u", f_num) |
3253 | 3254 | ||
3254 | fr = &cam->frame[f_num]; | 3255 | fr = &cam->frame[f_num]; |
3255 | 3256 | ||
3256 | switch (fr->status) { | 3257 | switch (fr->status) { |
3257 | case F_UNUSED: | 3258 | case F_UNUSED: |
3258 | if (!fr->queued) { | 3259 | if (!fr->queued) { |
3259 | DBG(4, "VIDIOSYNC: Frame #%u not requested!", | 3260 | DBG(4, "VIDIOSYNC: Frame #%u not requested!", |
3260 | f_num) | 3261 | f_num) |
3261 | return -EFAULT; | 3262 | return -EFAULT; |
3262 | } | 3263 | } |
3263 | case F_ERROR: | 3264 | case F_ERROR: |
3264 | case F_GRABBING: | 3265 | case F_GRABBING: |
3265 | err = wait_event_interruptible(cam->wait_queue, | 3266 | err = wait_event_interruptible(cam->wait_queue, |
3266 | (fr->status == F_READY) | 3267 | (fr->status == F_READY) |
3267 | || cam->disconnected); | 3268 | || cam->disconnected); |
3268 | if (err) | 3269 | if (err) |
3269 | return err; | 3270 | return err; |
3270 | if (cam->disconnected) | 3271 | if (cam->disconnected) |
3271 | return -ENODEV; | 3272 | return -ENODEV; |
3272 | break; | 3273 | break; |
3273 | case F_READY: | 3274 | case F_READY: |
3274 | break; | 3275 | break; |
3275 | } | 3276 | } |
3276 | 3277 | ||
3277 | if (w9968cf_vpp) | 3278 | if (w9968cf_vpp) |
3278 | w9968cf_postprocess_frame(cam, fr); | 3279 | w9968cf_postprocess_frame(cam, fr); |
3279 | 3280 | ||
3280 | fr->status = F_UNUSED; | 3281 | fr->status = F_UNUSED; |
3281 | 3282 | ||
3282 | DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) | 3283 | DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) |
3283 | return 0; | 3284 | return 0; |
3284 | } | 3285 | } |
3285 | 3286 | ||
3286 | case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ | 3287 | case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ |
3287 | { | 3288 | { |
3288 | struct video_unit unit = { | 3289 | struct video_unit unit = { |
3289 | .video = cam->v4ldev->minor, | 3290 | .video = cam->v4ldev->minor, |
3290 | .vbi = VIDEO_NO_UNIT, | 3291 | .vbi = VIDEO_NO_UNIT, |
3291 | .radio = VIDEO_NO_UNIT, | 3292 | .radio = VIDEO_NO_UNIT, |
3292 | .audio = VIDEO_NO_UNIT, | 3293 | .audio = VIDEO_NO_UNIT, |
3293 | .teletext = VIDEO_NO_UNIT, | 3294 | .teletext = VIDEO_NO_UNIT, |
3294 | }; | 3295 | }; |
3295 | 3296 | ||
3296 | if (copy_to_user(arg, &unit, sizeof(unit))) | 3297 | if (copy_to_user(arg, &unit, sizeof(unit))) |
3297 | return -EFAULT; | 3298 | return -EFAULT; |
3298 | 3299 | ||
3299 | DBG(5, "VIDIOCGUNIT successfully called") | 3300 | DBG(5, "VIDIOCGUNIT successfully called") |
3300 | return 0; | 3301 | return 0; |
3301 | } | 3302 | } |
3302 | 3303 | ||
3303 | case VIDIOCKEY: | 3304 | case VIDIOCKEY: |
3304 | return 0; | 3305 | return 0; |
3305 | 3306 | ||
3306 | case VIDIOCGFBUF: | 3307 | case VIDIOCGFBUF: |
3307 | { | 3308 | { |
3308 | if (clear_user(arg, sizeof(struct video_buffer))) | 3309 | if (clear_user(arg, sizeof(struct video_buffer))) |
3309 | return -EFAULT; | 3310 | return -EFAULT; |
3310 | 3311 | ||
3311 | DBG(5, "VIDIOCGFBUF successfully called") | 3312 | DBG(5, "VIDIOCGFBUF successfully called") |
3312 | return 0; | 3313 | return 0; |
3313 | } | 3314 | } |
3314 | 3315 | ||
3315 | case VIDIOCGTUNER: | 3316 | case VIDIOCGTUNER: |
3316 | { | 3317 | { |
3317 | struct video_tuner tuner; | 3318 | struct video_tuner tuner; |
3318 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | 3319 | if (copy_from_user(&tuner, arg, sizeof(tuner))) |
3319 | return -EFAULT; | 3320 | return -EFAULT; |
3320 | 3321 | ||
3321 | if (tuner.tuner != 0) | 3322 | if (tuner.tuner != 0) |
3322 | return -EINVAL; | 3323 | return -EINVAL; |
3323 | 3324 | ||
3324 | strcpy(tuner.name, "no_tuner"); | 3325 | strcpy(tuner.name, "no_tuner"); |
3325 | tuner.rangelow = 0; | 3326 | tuner.rangelow = 0; |
3326 | tuner.rangehigh = 0; | 3327 | tuner.rangehigh = 0; |
3327 | tuner.flags = VIDEO_TUNER_NORM; | 3328 | tuner.flags = VIDEO_TUNER_NORM; |
3328 | tuner.mode = VIDEO_MODE_AUTO; | 3329 | tuner.mode = VIDEO_MODE_AUTO; |
3329 | tuner.signal = 0xffff; | 3330 | tuner.signal = 0xffff; |
3330 | 3331 | ||
3331 | if (copy_to_user(arg, &tuner, sizeof(tuner))) | 3332 | if (copy_to_user(arg, &tuner, sizeof(tuner))) |
3332 | return -EFAULT; | 3333 | return -EFAULT; |
3333 | 3334 | ||
3334 | DBG(5, "VIDIOCGTUNER successfully called") | 3335 | DBG(5, "VIDIOCGTUNER successfully called") |
3335 | return 0; | 3336 | return 0; |
3336 | } | 3337 | } |
3337 | 3338 | ||
3338 | case VIDIOCSTUNER: | 3339 | case VIDIOCSTUNER: |
3339 | { | 3340 | { |
3340 | struct video_tuner tuner; | 3341 | struct video_tuner tuner; |
3341 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | 3342 | if (copy_from_user(&tuner, arg, sizeof(tuner))) |
3342 | return -EFAULT; | 3343 | return -EFAULT; |
3343 | 3344 | ||
3344 | if (tuner.tuner != 0) | 3345 | if (tuner.tuner != 0) |
3345 | return -EINVAL; | 3346 | return -EINVAL; |
3346 | 3347 | ||
3347 | if (tuner.mode != VIDEO_MODE_AUTO) | 3348 | if (tuner.mode != VIDEO_MODE_AUTO) |
3348 | return -EINVAL; | 3349 | return -EINVAL; |
3349 | 3350 | ||
3350 | DBG(5, "VIDIOCSTUNER successfully called") | 3351 | DBG(5, "VIDIOCSTUNER successfully called") |
3351 | return 0; | 3352 | return 0; |
3352 | } | 3353 | } |
3353 | 3354 | ||
3354 | case VIDIOCSFBUF: | 3355 | case VIDIOCSFBUF: |
3355 | case VIDIOCCAPTURE: | 3356 | case VIDIOCCAPTURE: |
3356 | case VIDIOCGFREQ: | 3357 | case VIDIOCGFREQ: |
3357 | case VIDIOCSFREQ: | 3358 | case VIDIOCSFREQ: |
3358 | case VIDIOCGAUDIO: | 3359 | case VIDIOCGAUDIO: |
3359 | case VIDIOCSAUDIO: | 3360 | case VIDIOCSAUDIO: |
3360 | case VIDIOCSPLAYMODE: | 3361 | case VIDIOCSPLAYMODE: |
3361 | case VIDIOCSWRITEMODE: | 3362 | case VIDIOCSWRITEMODE: |
3362 | case VIDIOCGPLAYINFO: | 3363 | case VIDIOCGPLAYINFO: |
3363 | case VIDIOCSMICROCODE: | 3364 | case VIDIOCSMICROCODE: |
3364 | case VIDIOCGVBIFMT: | 3365 | case VIDIOCGVBIFMT: |
3365 | case VIDIOCSVBIFMT: | 3366 | case VIDIOCSVBIFMT: |
3366 | DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " | 3367 | DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " |
3367 | "(type 0x%01X, " | 3368 | "(type 0x%01X, " |
3368 | "n. 0x%01X, " | 3369 | "n. 0x%01X, " |
3369 | "dir. 0x%01X, " | 3370 | "dir. 0x%01X, " |
3370 | "size 0x%02X)", | 3371 | "size 0x%02X)", |
3371 | V4L1_IOCTL(cmd), | 3372 | V4L1_IOCTL(cmd), |
3372 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | 3373 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) |
3373 | 3374 | ||
3374 | return -EINVAL; | 3375 | return -EINVAL; |
3375 | 3376 | ||
3376 | default: | 3377 | default: |
3377 | DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " | 3378 | DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " |
3378 | "type 0x%01X, " | 3379 | "type 0x%01X, " |
3379 | "n. 0x%01X, " | 3380 | "n. 0x%01X, " |
3380 | "dir. 0x%01X, " | 3381 | "dir. 0x%01X, " |
3381 | "size 0x%02X", | 3382 | "size 0x%02X", |
3382 | V4L1_IOCTL(cmd), | 3383 | V4L1_IOCTL(cmd), |
3383 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | 3384 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) |
3384 | 3385 | ||
3385 | return -ENOIOCTLCMD; | 3386 | return -ENOIOCTLCMD; |
3386 | 3387 | ||
3387 | } /* end of switch */ | 3388 | } /* end of switch */ |
3388 | 3389 | ||
3389 | ioctl_fail: | 3390 | ioctl_fail: |
3390 | cam->misconfigured = 1; | 3391 | cam->misconfigured = 1; |
3391 | DBG(1, "VIDIOC%s failed because of hardware problems. " | 3392 | DBG(1, "VIDIOC%s failed because of hardware problems. " |
3392 | "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) | 3393 | "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) |
3393 | return -EFAULT; | 3394 | return -EFAULT; |
3394 | } | 3395 | } |
3395 | 3396 | ||
3396 | 3397 | ||
3397 | static const struct v4l2_file_operations w9968cf_fops = { | 3398 | static const struct v4l2_file_operations w9968cf_fops = { |
3398 | .owner = THIS_MODULE, | 3399 | .owner = THIS_MODULE, |
3399 | .open = w9968cf_open, | 3400 | .open = w9968cf_open, |
3400 | .release = w9968cf_release, | 3401 | .release = w9968cf_release, |
3401 | .read = w9968cf_read, | 3402 | .read = w9968cf_read, |
3402 | .ioctl = w9968cf_ioctl, | 3403 | .ioctl = w9968cf_ioctl, |
3403 | .mmap = w9968cf_mmap, | 3404 | .mmap = w9968cf_mmap, |
3404 | }; | 3405 | }; |
3405 | 3406 | ||
3406 | 3407 | ||
3407 | 3408 | ||
3408 | /**************************************************************************** | 3409 | /**************************************************************************** |
3409 | * USB probe and V4L registration, disconnect and id_table[] definition * | 3410 | * USB probe and V4L registration, disconnect and id_table[] definition * |
3410 | ****************************************************************************/ | 3411 | ****************************************************************************/ |
3411 | 3412 | ||
3412 | static int | 3413 | static int |
3413 | w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | 3414 | w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) |
3414 | { | 3415 | { |
3415 | struct usb_device *udev = interface_to_usbdev(intf); | 3416 | struct usb_device *udev = interface_to_usbdev(intf); |
3416 | struct w9968cf_device* cam; | 3417 | struct w9968cf_device* cam; |
3417 | int err = 0; | 3418 | int err = 0; |
3418 | enum w9968cf_model_id mod_id; | 3419 | enum w9968cf_model_id mod_id; |
3419 | struct list_head* ptr; | 3420 | struct list_head* ptr; |
3420 | u8 sc = 0; /* number of simultaneous cameras */ | 3421 | u8 sc = 0; /* number of simultaneous cameras */ |
3421 | static unsigned short dev_nr; /* 0 - we are handling device number n */ | 3422 | static unsigned short dev_nr; /* 0 - we are handling device number n */ |
3422 | static unsigned short addrs[] = { | 3423 | static unsigned short addrs[] = { |
3423 | OV7xx0_SID, | 3424 | OV7xx0_SID, |
3424 | OV6xx0_SID, | 3425 | OV6xx0_SID, |
3425 | I2C_CLIENT_END | 3426 | I2C_CLIENT_END |
3426 | }; | 3427 | }; |
3427 | 3428 | ||
3428 | if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && | 3429 | if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && |
3429 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) | 3430 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) |
3430 | mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ | 3431 | mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ |
3431 | else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && | 3432 | else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && |
3432 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) | 3433 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) |
3433 | mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ | 3434 | mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ |
3434 | else | 3435 | else |
3435 | return -ENODEV; | 3436 | return -ENODEV; |
3436 | 3437 | ||
3437 | cam = (struct w9968cf_device*) | 3438 | cam = (struct w9968cf_device*) |
3438 | kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); | 3439 | kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); |
3439 | if (!cam) | 3440 | if (!cam) |
3440 | return -ENOMEM; | 3441 | return -ENOMEM; |
3441 | 3442 | ||
3442 | err = v4l2_device_register(&udev->dev, &cam->v4l2_dev); | 3443 | err = v4l2_device_register(&udev->dev, &cam->v4l2_dev); |
3443 | if (err) | 3444 | if (err) |
3444 | goto fail0; | 3445 | goto fail0; |
3445 | 3446 | ||
3446 | mutex_init(&cam->dev_mutex); | 3447 | mutex_init(&cam->dev_mutex); |
3447 | mutex_lock(&cam->dev_mutex); | 3448 | mutex_lock(&cam->dev_mutex); |
3448 | 3449 | ||
3449 | cam->usbdev = udev; | 3450 | cam->usbdev = udev; |
3450 | 3451 | ||
3451 | DBG(2, "%s detected", symbolic(camlist, mod_id)) | 3452 | DBG(2, "%s detected", symbolic(camlist, mod_id)) |
3452 | 3453 | ||
3453 | if (simcams > W9968CF_MAX_DEVICES) | 3454 | if (simcams > W9968CF_MAX_DEVICES) |
3454 | simcams = W9968CF_SIMCAMS; | 3455 | simcams = W9968CF_SIMCAMS; |
3455 | 3456 | ||
3456 | /* How many cameras are connected ? */ | 3457 | /* How many cameras are connected ? */ |
3457 | mutex_lock(&w9968cf_devlist_mutex); | 3458 | mutex_lock(&w9968cf_devlist_mutex); |
3458 | list_for_each(ptr, &w9968cf_dev_list) | 3459 | list_for_each(ptr, &w9968cf_dev_list) |
3459 | sc++; | 3460 | sc++; |
3460 | mutex_unlock(&w9968cf_devlist_mutex); | 3461 | mutex_unlock(&w9968cf_devlist_mutex); |
3461 | 3462 | ||
3462 | if (sc >= simcams) { | 3463 | if (sc >= simcams) { |
3463 | DBG(2, "Device rejected: too many connected cameras " | 3464 | DBG(2, "Device rejected: too many connected cameras " |
3464 | "(max. %u)", simcams) | 3465 | "(max. %u)", simcams) |
3465 | err = -EPERM; | 3466 | err = -EPERM; |
3466 | goto fail; | 3467 | goto fail; |
3467 | } | 3468 | } |
3468 | 3469 | ||
3469 | 3470 | ||
3470 | /* Allocate 2 bytes of memory for camera control USB transfers */ | 3471 | /* Allocate 2 bytes of memory for camera control USB transfers */ |
3471 | if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { | 3472 | if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { |
3472 | DBG(1,"Couldn't allocate memory for camera control transfers") | 3473 | DBG(1,"Couldn't allocate memory for camera control transfers") |
3473 | err = -ENOMEM; | 3474 | err = -ENOMEM; |
3474 | goto fail; | 3475 | goto fail; |
3475 | } | 3476 | } |
3476 | 3477 | ||
3477 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ | 3478 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ |
3478 | if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { | 3479 | if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { |
3479 | DBG(1, "Couldn't allocate memory for data " | 3480 | DBG(1, "Couldn't allocate memory for data " |
3480 | "transfers to the FSB") | 3481 | "transfers to the FSB") |
3481 | err = -ENOMEM; | 3482 | err = -ENOMEM; |
3482 | goto fail; | 3483 | goto fail; |
3483 | } | 3484 | } |
3484 | 3485 | ||
3485 | /* Register the V4L device */ | 3486 | /* Register the V4L device */ |
3486 | cam->v4ldev = video_device_alloc(); | 3487 | cam->v4ldev = video_device_alloc(); |
3487 | if (!cam->v4ldev) { | 3488 | if (!cam->v4ldev) { |
3488 | DBG(1, "Could not allocate memory for a V4L structure") | 3489 | DBG(1, "Could not allocate memory for a V4L structure") |
3489 | err = -ENOMEM; | 3490 | err = -ENOMEM; |
3490 | goto fail; | 3491 | goto fail; |
3491 | } | 3492 | } |
3492 | 3493 | ||
3493 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); | 3494 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); |
3494 | cam->v4ldev->fops = &w9968cf_fops; | 3495 | cam->v4ldev->fops = &w9968cf_fops; |
3495 | cam->v4ldev->minor = video_nr[dev_nr]; | 3496 | cam->v4ldev->minor = video_nr[dev_nr]; |
3496 | cam->v4ldev->release = video_device_release; | 3497 | cam->v4ldev->release = video_device_release; |
3497 | video_set_drvdata(cam->v4ldev, cam); | 3498 | video_set_drvdata(cam->v4ldev, cam); |
3498 | cam->v4ldev->v4l2_dev = &cam->v4l2_dev; | 3499 | cam->v4ldev->v4l2_dev = &cam->v4l2_dev; |
3499 | 3500 | ||
3500 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | 3501 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, |
3501 | video_nr[dev_nr]); | 3502 | video_nr[dev_nr]); |
3502 | if (err) { | 3503 | if (err) { |
3503 | DBG(1, "V4L device registration failed") | 3504 | DBG(1, "V4L device registration failed") |
3504 | if (err == -ENFILE && video_nr[dev_nr] == -1) | 3505 | if (err == -ENFILE && video_nr[dev_nr] == -1) |
3505 | DBG(2, "Couldn't find a free /dev/videoX node") | 3506 | DBG(2, "Couldn't find a free /dev/videoX node") |
3506 | video_nr[dev_nr] = -1; | 3507 | video_nr[dev_nr] = -1; |
3507 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | 3508 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; |
3508 | goto fail; | 3509 | goto fail; |
3509 | } | 3510 | } |
3510 | 3511 | ||
3511 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num) | 3512 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num) |
3512 | 3513 | ||
3513 | /* Set some basic constants */ | 3514 | /* Set some basic constants */ |
3514 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | 3515 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); |
3515 | 3516 | ||
3516 | /* Add a new entry into the list of V4L registered devices */ | 3517 | /* Add a new entry into the list of V4L registered devices */ |
3517 | mutex_lock(&w9968cf_devlist_mutex); | 3518 | mutex_lock(&w9968cf_devlist_mutex); |
3518 | list_add(&cam->v4llist, &w9968cf_dev_list); | 3519 | list_add(&cam->v4llist, &w9968cf_dev_list); |
3519 | mutex_unlock(&w9968cf_devlist_mutex); | 3520 | mutex_unlock(&w9968cf_devlist_mutex); |
3520 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | 3521 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; |
3521 | 3522 | ||
3522 | w9968cf_turn_on_led(cam); | 3523 | w9968cf_turn_on_led(cam); |
3523 | 3524 | ||
3524 | w9968cf_i2c_init(cam); | 3525 | w9968cf_i2c_init(cam); |
3525 | cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter, | 3526 | cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter, |
3526 | "ovcamchip", "ovcamchip", addrs); | 3527 | "ovcamchip", "ovcamchip", addrs); |
3527 | 3528 | ||
3528 | usb_set_intfdata(intf, cam); | 3529 | usb_set_intfdata(intf, cam); |
3529 | mutex_unlock(&cam->dev_mutex); | 3530 | mutex_unlock(&cam->dev_mutex); |
3530 | 3531 | ||
3531 | err = w9968cf_sensor_init(cam); | 3532 | err = w9968cf_sensor_init(cam); |
3532 | return 0; | 3533 | return 0; |
3533 | 3534 | ||
3534 | fail: /* Free unused memory */ | 3535 | fail: /* Free unused memory */ |
3535 | kfree(cam->control_buffer); | 3536 | kfree(cam->control_buffer); |
3536 | kfree(cam->data_buffer); | 3537 | kfree(cam->data_buffer); |
3537 | if (cam->v4ldev) | 3538 | if (cam->v4ldev) |
3538 | video_device_release(cam->v4ldev); | 3539 | video_device_release(cam->v4ldev); |
3539 | mutex_unlock(&cam->dev_mutex); | 3540 | mutex_unlock(&cam->dev_mutex); |
3540 | v4l2_device_unregister(&cam->v4l2_dev); | 3541 | v4l2_device_unregister(&cam->v4l2_dev); |
3541 | fail0: | 3542 | fail0: |
3542 | kfree(cam); | 3543 | kfree(cam); |
3543 | return err; | 3544 | return err; |
3544 | } | 3545 | } |
3545 | 3546 | ||
3546 | 3547 | ||
3547 | static void w9968cf_usb_disconnect(struct usb_interface* intf) | 3548 | static void w9968cf_usb_disconnect(struct usb_interface* intf) |
3548 | { | 3549 | { |
3549 | struct w9968cf_device* cam = | 3550 | struct w9968cf_device* cam = |
3550 | (struct w9968cf_device*)usb_get_intfdata(intf); | 3551 | (struct w9968cf_device*)usb_get_intfdata(intf); |
3551 | 3552 | ||
3552 | if (cam) { | 3553 | if (cam) { |
3553 | down_write(&w9968cf_disconnect); | 3554 | down_write(&w9968cf_disconnect); |
3554 | /* Prevent concurrent accesses to data */ | 3555 | /* Prevent concurrent accesses to data */ |
3555 | mutex_lock(&cam->dev_mutex); | 3556 | mutex_lock(&cam->dev_mutex); |
3556 | 3557 | ||
3557 | cam->disconnected = 1; | 3558 | cam->disconnected = 1; |
3558 | 3559 | ||
3559 | DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) | 3560 | DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) |
3560 | 3561 | ||
3561 | wake_up_interruptible_all(&cam->open); | 3562 | wake_up_interruptible_all(&cam->open); |
3562 | 3563 | ||
3563 | if (cam->users) { | 3564 | if (cam->users) { |
3564 | DBG(2, "The device is open (/dev/video%d)! " | 3565 | DBG(2, "The device is open (/dev/video%d)! " |
3565 | "Process name: %s. Deregistration and memory " | 3566 | "Process name: %s. Deregistration and memory " |
3566 | "deallocation are deferred on close.", | 3567 | "deallocation are deferred on close.", |
3567 | cam->v4ldev->num, cam->command) | 3568 | cam->v4ldev->num, cam->command) |
3568 | cam->misconfigured = 1; | 3569 | cam->misconfigured = 1; |
3569 | w9968cf_stop_transfer(cam); | 3570 | w9968cf_stop_transfer(cam); |
3570 | wake_up_interruptible(&cam->wait_queue); | 3571 | wake_up_interruptible(&cam->wait_queue); |
3571 | } else | 3572 | } else |
3572 | w9968cf_release_resources(cam); | 3573 | w9968cf_release_resources(cam); |
3573 | 3574 | ||
3574 | mutex_unlock(&cam->dev_mutex); | 3575 | mutex_unlock(&cam->dev_mutex); |
3575 | up_write(&w9968cf_disconnect); | 3576 | up_write(&w9968cf_disconnect); |
3576 | 3577 | ||
3577 | if (!cam->users) { | 3578 | if (!cam->users) { |
3578 | kfree(cam); | 3579 | kfree(cam); |
3579 | } | 3580 | } |
3580 | } | 3581 | } |
3581 | } | 3582 | } |
3582 | 3583 | ||
3583 | 3584 | ||
3584 | static struct usb_driver w9968cf_usb_driver = { | 3585 | static struct usb_driver w9968cf_usb_driver = { |
3585 | .name = "w9968cf", | 3586 | .name = "w9968cf", |
3586 | .id_table = winbond_id_table, | 3587 | .id_table = winbond_id_table, |
3587 | .probe = w9968cf_usb_probe, | 3588 | .probe = w9968cf_usb_probe, |
3588 | .disconnect = w9968cf_usb_disconnect, | 3589 | .disconnect = w9968cf_usb_disconnect, |
3589 | }; | 3590 | }; |
3590 | 3591 | ||
3591 | 3592 | ||
3592 | 3593 | ||
3593 | /**************************************************************************** | 3594 | /**************************************************************************** |
3594 | * Module init, exit and intermodule communication * | 3595 | * Module init, exit and intermodule communication * |
3595 | ****************************************************************************/ | 3596 | ****************************************************************************/ |
3596 | 3597 | ||
3597 | static int __init w9968cf_module_init(void) | 3598 | static int __init w9968cf_module_init(void) |
3598 | { | 3599 | { |
3599 | int err; | 3600 | int err; |
3600 | 3601 | ||
3601 | KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) | 3602 | KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) |
3602 | KDBG(3, W9968CF_MODULE_AUTHOR) | 3603 | KDBG(3, W9968CF_MODULE_AUTHOR) |
3603 | 3604 | ||
3604 | if ((err = usb_register(&w9968cf_usb_driver))) | 3605 | if ((err = usb_register(&w9968cf_usb_driver))) |
3605 | return err; | 3606 | return err; |
3606 | 3607 | ||
3607 | return 0; | 3608 | return 0; |
3608 | } | 3609 | } |
3609 | 3610 | ||
3610 | 3611 | ||
3611 | static void __exit w9968cf_module_exit(void) | 3612 | static void __exit w9968cf_module_exit(void) |
3612 | { | 3613 | { |
3613 | /* w9968cf_usb_disconnect() will be called */ | 3614 | /* w9968cf_usb_disconnect() will be called */ |
3614 | usb_deregister(&w9968cf_usb_driver); | 3615 | usb_deregister(&w9968cf_usb_driver); |
3615 | 3616 | ||
3616 | KDBG(2, W9968CF_MODULE_NAME" deregistered") | 3617 | KDBG(2, W9968CF_MODULE_NAME" deregistered") |
3617 | } | 3618 | } |
3618 | 3619 | ||
3619 | 3620 | ||
3620 | module_init(w9968cf_module_init); | 3621 | module_init(w9968cf_module_init); |
3621 | module_exit(w9968cf_module_exit); | 3622 | module_exit(w9968cf_module_exit); |
3622 | 3623 | ||
3623 | 3624 |
drivers/media/video/zoran/zoran_driver.c
1 | /* | 1 | /* |
2 | * Zoran zr36057/zr36067 PCI controller driver, for the | 2 | * Zoran zr36057/zr36067 PCI controller driver, for the |
3 | * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux | 3 | * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux |
4 | * Media Labs LML33/LML33R10. | 4 | * Media Labs LML33/LML33R10. |
5 | * | 5 | * |
6 | * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> | 6 | * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> |
7 | * | 7 | * |
8 | * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> | 8 | * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> |
9 | * | 9 | * |
10 | * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> | 10 | * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> |
11 | * | 11 | * |
12 | * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> | 12 | * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> |
13 | * | 13 | * |
14 | * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> | 14 | * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> |
15 | * | 15 | * |
16 | * Based on | 16 | * Based on |
17 | * | 17 | * |
18 | * Miro DC10 driver | 18 | * Miro DC10 driver |
19 | * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> | 19 | * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> |
20 | * | 20 | * |
21 | * Iomega Buz driver version 1.0 | 21 | * Iomega Buz driver version 1.0 |
22 | * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> | 22 | * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> |
23 | * | 23 | * |
24 | * buz.0.0.3 | 24 | * buz.0.0.3 |
25 | * Copyright (C) 1998 Dave Perks <dperks@ibm.net> | 25 | * Copyright (C) 1998 Dave Perks <dperks@ibm.net> |
26 | * | 26 | * |
27 | * bttv - Bt848 frame grabber driver | 27 | * bttv - Bt848 frame grabber driver |
28 | * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) | 28 | * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) |
29 | * & Marcus Metzler (mocm@thp.uni-koeln.de) | 29 | * & Marcus Metzler (mocm@thp.uni-koeln.de) |
30 | * | 30 | * |
31 | * | 31 | * |
32 | * This program is free software; you can redistribute it and/or modify | 32 | * This program is free software; you can redistribute it and/or modify |
33 | * it under the terms of the GNU General Public License as published by | 33 | * it under the terms of the GNU General Public License as published by |
34 | * the Free Software Foundation; either version 2 of the License, or | 34 | * the Free Software Foundation; either version 2 of the License, or |
35 | * (at your option) any later version. | 35 | * (at your option) any later version. |
36 | * | 36 | * |
37 | * This program is distributed in the hope that it will be useful, | 37 | * This program is distributed in the hope that it will be useful, |
38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
40 | * GNU General Public License for more details. | 40 | * GNU General Public License for more details. |
41 | * | 41 | * |
42 | * You should have received a copy of the GNU General Public License | 42 | * You should have received a copy of the GNU General Public License |
43 | * along with this program; if not, write to the Free Software | 43 | * along with this program; if not, write to the Free Software |
44 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 44 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
45 | */ | 45 | */ |
46 | 46 | ||
47 | #include <linux/version.h> | 47 | #include <linux/version.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/module.h> | 49 | #include <linux/module.h> |
50 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
51 | #include <linux/slab.h> | 51 | #include <linux/slab.h> |
52 | #include <linux/pci.h> | 52 | #include <linux/pci.h> |
53 | #include <linux/vmalloc.h> | 53 | #include <linux/vmalloc.h> |
54 | #include <linux/wait.h> | 54 | #include <linux/wait.h> |
55 | 55 | ||
56 | #include <linux/interrupt.h> | 56 | #include <linux/interrupt.h> |
57 | #include <linux/i2c.h> | 57 | #include <linux/i2c.h> |
58 | #include <linux/i2c-algo-bit.h> | 58 | #include <linux/i2c-algo-bit.h> |
59 | 59 | ||
60 | #include <linux/spinlock.h> | 60 | #include <linux/spinlock.h> |
61 | 61 | ||
62 | #include <linux/videodev2.h> | 62 | #include <linux/videodev.h> |
63 | #include <media/v4l2-common.h> | 63 | #include <media/v4l2-common.h> |
64 | #include <media/v4l2-ioctl.h> | 64 | #include <media/v4l2-ioctl.h> |
65 | #include "videocodec.h" | 65 | #include "videocodec.h" |
66 | 66 | ||
67 | #include <asm/byteorder.h> | 67 | #include <asm/byteorder.h> |
68 | #include <asm/io.h> | 68 | #include <asm/io.h> |
69 | #include <asm/uaccess.h> | 69 | #include <asm/uaccess.h> |
70 | #include <linux/proc_fs.h> | 70 | #include <linux/proc_fs.h> |
71 | 71 | ||
72 | #include <linux/mutex.h> | 72 | #include <linux/mutex.h> |
73 | #include "zoran.h" | 73 | #include "zoran.h" |
74 | #include "zoran_device.h" | 74 | #include "zoran_device.h" |
75 | #include "zoran_card.h" | 75 | #include "zoran_card.h" |
76 | 76 | ||
77 | 77 | ||
78 | const struct zoran_format zoran_formats[] = { | 78 | const struct zoran_format zoran_formats[] = { |
79 | { | 79 | { |
80 | .name = "15-bit RGB LE", | 80 | .name = "15-bit RGB LE", |
81 | .fourcc = V4L2_PIX_FMT_RGB555, | 81 | .fourcc = V4L2_PIX_FMT_RGB555, |
82 | .colorspace = V4L2_COLORSPACE_SRGB, | 82 | .colorspace = V4L2_COLORSPACE_SRGB, |
83 | .depth = 15, | 83 | .depth = 15, |
84 | .flags = ZORAN_FORMAT_CAPTURE | | 84 | .flags = ZORAN_FORMAT_CAPTURE | |
85 | ZORAN_FORMAT_OVERLAY, | 85 | ZORAN_FORMAT_OVERLAY, |
86 | .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif| | 86 | .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif| |
87 | ZR36057_VFESPFR_LittleEndian, | 87 | ZR36057_VFESPFR_LittleEndian, |
88 | }, { | 88 | }, { |
89 | .name = "15-bit RGB BE", | 89 | .name = "15-bit RGB BE", |
90 | .fourcc = V4L2_PIX_FMT_RGB555X, | 90 | .fourcc = V4L2_PIX_FMT_RGB555X, |
91 | .colorspace = V4L2_COLORSPACE_SRGB, | 91 | .colorspace = V4L2_COLORSPACE_SRGB, |
92 | .depth = 15, | 92 | .depth = 15, |
93 | .flags = ZORAN_FORMAT_CAPTURE | | 93 | .flags = ZORAN_FORMAT_CAPTURE | |
94 | ZORAN_FORMAT_OVERLAY, | 94 | ZORAN_FORMAT_OVERLAY, |
95 | .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif, | 95 | .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif, |
96 | }, { | 96 | }, { |
97 | .name = "16-bit RGB LE", | 97 | .name = "16-bit RGB LE", |
98 | .fourcc = V4L2_PIX_FMT_RGB565, | 98 | .fourcc = V4L2_PIX_FMT_RGB565, |
99 | .colorspace = V4L2_COLORSPACE_SRGB, | 99 | .colorspace = V4L2_COLORSPACE_SRGB, |
100 | .depth = 16, | 100 | .depth = 16, |
101 | .flags = ZORAN_FORMAT_CAPTURE | | 101 | .flags = ZORAN_FORMAT_CAPTURE | |
102 | ZORAN_FORMAT_OVERLAY, | 102 | ZORAN_FORMAT_OVERLAY, |
103 | .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif| | 103 | .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif| |
104 | ZR36057_VFESPFR_LittleEndian, | 104 | ZR36057_VFESPFR_LittleEndian, |
105 | }, { | 105 | }, { |
106 | .name = "16-bit RGB BE", | 106 | .name = "16-bit RGB BE", |
107 | .fourcc = V4L2_PIX_FMT_RGB565X, | 107 | .fourcc = V4L2_PIX_FMT_RGB565X, |
108 | .colorspace = V4L2_COLORSPACE_SRGB, | 108 | .colorspace = V4L2_COLORSPACE_SRGB, |
109 | .depth = 16, | 109 | .depth = 16, |
110 | .flags = ZORAN_FORMAT_CAPTURE | | 110 | .flags = ZORAN_FORMAT_CAPTURE | |
111 | ZORAN_FORMAT_OVERLAY, | 111 | ZORAN_FORMAT_OVERLAY, |
112 | .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif, | 112 | .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif, |
113 | }, { | 113 | }, { |
114 | .name = "24-bit RGB", | 114 | .name = "24-bit RGB", |
115 | .fourcc = V4L2_PIX_FMT_BGR24, | 115 | .fourcc = V4L2_PIX_FMT_BGR24, |
116 | .colorspace = V4L2_COLORSPACE_SRGB, | 116 | .colorspace = V4L2_COLORSPACE_SRGB, |
117 | .depth = 24, | 117 | .depth = 24, |
118 | .flags = ZORAN_FORMAT_CAPTURE | | 118 | .flags = ZORAN_FORMAT_CAPTURE | |
119 | ZORAN_FORMAT_OVERLAY, | 119 | ZORAN_FORMAT_OVERLAY, |
120 | .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24, | 120 | .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24, |
121 | }, { | 121 | }, { |
122 | .name = "32-bit RGB LE", | 122 | .name = "32-bit RGB LE", |
123 | .fourcc = V4L2_PIX_FMT_BGR32, | 123 | .fourcc = V4L2_PIX_FMT_BGR32, |
124 | .colorspace = V4L2_COLORSPACE_SRGB, | 124 | .colorspace = V4L2_COLORSPACE_SRGB, |
125 | .depth = 32, | 125 | .depth = 32, |
126 | .flags = ZORAN_FORMAT_CAPTURE | | 126 | .flags = ZORAN_FORMAT_CAPTURE | |
127 | ZORAN_FORMAT_OVERLAY, | 127 | ZORAN_FORMAT_OVERLAY, |
128 | .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian, | 128 | .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian, |
129 | }, { | 129 | }, { |
130 | .name = "32-bit RGB BE", | 130 | .name = "32-bit RGB BE", |
131 | .fourcc = V4L2_PIX_FMT_RGB32, | 131 | .fourcc = V4L2_PIX_FMT_RGB32, |
132 | .colorspace = V4L2_COLORSPACE_SRGB, | 132 | .colorspace = V4L2_COLORSPACE_SRGB, |
133 | .depth = 32, | 133 | .depth = 32, |
134 | .flags = ZORAN_FORMAT_CAPTURE | | 134 | .flags = ZORAN_FORMAT_CAPTURE | |
135 | ZORAN_FORMAT_OVERLAY, | 135 | ZORAN_FORMAT_OVERLAY, |
136 | .vfespfr = ZR36057_VFESPFR_RGB888, | 136 | .vfespfr = ZR36057_VFESPFR_RGB888, |
137 | }, { | 137 | }, { |
138 | .name = "4:2:2, packed, YUYV", | 138 | .name = "4:2:2, packed, YUYV", |
139 | .fourcc = V4L2_PIX_FMT_YUYV, | 139 | .fourcc = V4L2_PIX_FMT_YUYV, |
140 | .colorspace = V4L2_COLORSPACE_SMPTE170M, | 140 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
141 | .depth = 16, | 141 | .depth = 16, |
142 | .flags = ZORAN_FORMAT_CAPTURE | | 142 | .flags = ZORAN_FORMAT_CAPTURE | |
143 | ZORAN_FORMAT_OVERLAY, | 143 | ZORAN_FORMAT_OVERLAY, |
144 | .vfespfr = ZR36057_VFESPFR_YUV422, | 144 | .vfespfr = ZR36057_VFESPFR_YUV422, |
145 | }, { | 145 | }, { |
146 | .name = "4:2:2, packed, UYVY", | 146 | .name = "4:2:2, packed, UYVY", |
147 | .fourcc = V4L2_PIX_FMT_UYVY, | 147 | .fourcc = V4L2_PIX_FMT_UYVY, |
148 | .colorspace = V4L2_COLORSPACE_SMPTE170M, | 148 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
149 | .depth = 16, | 149 | .depth = 16, |
150 | .flags = ZORAN_FORMAT_CAPTURE | | 150 | .flags = ZORAN_FORMAT_CAPTURE | |
151 | ZORAN_FORMAT_OVERLAY, | 151 | ZORAN_FORMAT_OVERLAY, |
152 | .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian, | 152 | .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian, |
153 | }, { | 153 | }, { |
154 | .name = "Hardware-encoded Motion-JPEG", | 154 | .name = "Hardware-encoded Motion-JPEG", |
155 | .fourcc = V4L2_PIX_FMT_MJPEG, | 155 | .fourcc = V4L2_PIX_FMT_MJPEG, |
156 | .colorspace = V4L2_COLORSPACE_SMPTE170M, | 156 | .colorspace = V4L2_COLORSPACE_SMPTE170M, |
157 | .depth = 0, | 157 | .depth = 0, |
158 | .flags = ZORAN_FORMAT_CAPTURE | | 158 | .flags = ZORAN_FORMAT_CAPTURE | |
159 | ZORAN_FORMAT_PLAYBACK | | 159 | ZORAN_FORMAT_PLAYBACK | |
160 | ZORAN_FORMAT_COMPRESSED, | 160 | ZORAN_FORMAT_COMPRESSED, |
161 | } | 161 | } |
162 | }; | 162 | }; |
163 | #define NUM_FORMATS ARRAY_SIZE(zoran_formats) | 163 | #define NUM_FORMATS ARRAY_SIZE(zoran_formats) |
164 | 164 | ||
165 | static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */ | 165 | static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */ |
166 | module_param(lock_norm, int, 0644); | 166 | module_param(lock_norm, int, 0644); |
167 | MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); | 167 | MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); |
168 | 168 | ||
169 | /* small helper function for calculating buffersizes for v4l2 | 169 | /* small helper function for calculating buffersizes for v4l2 |
170 | * we calculate the nearest higher power-of-two, which | 170 | * we calculate the nearest higher power-of-two, which |
171 | * will be the recommended buffersize */ | 171 | * will be the recommended buffersize */ |
172 | static __u32 | 172 | static __u32 |
173 | zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings) | 173 | zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings) |
174 | { | 174 | { |
175 | __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm; | 175 | __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm; |
176 | __u32 num = (1024 * 512) / (div); | 176 | __u32 num = (1024 * 512) / (div); |
177 | __u32 result = 2; | 177 | __u32 result = 2; |
178 | 178 | ||
179 | num--; | 179 | num--; |
180 | while (num) { | 180 | while (num) { |
181 | num >>= 1; | 181 | num >>= 1; |
182 | result <<= 1; | 182 | result <<= 1; |
183 | } | 183 | } |
184 | 184 | ||
185 | if (result > jpg_bufsize) | 185 | if (result > jpg_bufsize) |
186 | return jpg_bufsize; | 186 | return jpg_bufsize; |
187 | if (result < 8192) | 187 | if (result < 8192) |
188 | return 8192; | 188 | return 8192; |
189 | return result; | 189 | return result; |
190 | } | 190 | } |
191 | 191 | ||
192 | /* forward references */ | 192 | /* forward references */ |
193 | static void v4l_fbuffer_free(struct file *file); | 193 | static void v4l_fbuffer_free(struct file *file); |
194 | static void jpg_fbuffer_free(struct file *file); | 194 | static void jpg_fbuffer_free(struct file *file); |
195 | 195 | ||
196 | /* | 196 | /* |
197 | * Allocate the V4L grab buffers | 197 | * Allocate the V4L grab buffers |
198 | * | 198 | * |
199 | * These have to be pysically contiguous. | 199 | * These have to be pysically contiguous. |
200 | */ | 200 | */ |
201 | 201 | ||
202 | static int | 202 | static int |
203 | v4l_fbuffer_alloc (struct file *file) | 203 | v4l_fbuffer_alloc (struct file *file) |
204 | { | 204 | { |
205 | struct zoran_fh *fh = file->private_data; | 205 | struct zoran_fh *fh = file->private_data; |
206 | struct zoran *zr = fh->zr; | 206 | struct zoran *zr = fh->zr; |
207 | int i, off; | 207 | int i, off; |
208 | unsigned char *mem; | 208 | unsigned char *mem; |
209 | 209 | ||
210 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { | 210 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { |
211 | if (fh->v4l_buffers.buffer[i].fbuffer) | 211 | if (fh->v4l_buffers.buffer[i].fbuffer) |
212 | dprintk(2, | 212 | dprintk(2, |
213 | KERN_WARNING | 213 | KERN_WARNING |
214 | "%s: v4l_fbuffer_alloc() - buffer %d already allocated!?\n", | 214 | "%s: v4l_fbuffer_alloc() - buffer %d already allocated!?\n", |
215 | ZR_DEVNAME(zr), i); | 215 | ZR_DEVNAME(zr), i); |
216 | 216 | ||
217 | //udelay(20); | 217 | //udelay(20); |
218 | mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); | 218 | mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); |
219 | if (!mem) { | 219 | if (!mem) { |
220 | dprintk(1, | 220 | dprintk(1, |
221 | KERN_ERR | 221 | KERN_ERR |
222 | "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n", | 222 | "%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n", |
223 | ZR_DEVNAME(zr), i); | 223 | ZR_DEVNAME(zr), i); |
224 | v4l_fbuffer_free(file); | 224 | v4l_fbuffer_free(file); |
225 | return -ENOBUFS; | 225 | return -ENOBUFS; |
226 | } | 226 | } |
227 | fh->v4l_buffers.buffer[i].fbuffer = mem; | 227 | fh->v4l_buffers.buffer[i].fbuffer = mem; |
228 | fh->v4l_buffers.buffer[i].fbuffer_phys = | 228 | fh->v4l_buffers.buffer[i].fbuffer_phys = |
229 | virt_to_phys(mem); | 229 | virt_to_phys(mem); |
230 | fh->v4l_buffers.buffer[i].fbuffer_bus = | 230 | fh->v4l_buffers.buffer[i].fbuffer_bus = |
231 | virt_to_bus(mem); | 231 | virt_to_bus(mem); |
232 | for (off = 0; off < fh->v4l_buffers.buffer_size; | 232 | for (off = 0; off < fh->v4l_buffers.buffer_size; |
233 | off += PAGE_SIZE) | 233 | off += PAGE_SIZE) |
234 | SetPageReserved(virt_to_page(mem + off)); | 234 | SetPageReserved(virt_to_page(mem + off)); |
235 | dprintk(4, | 235 | dprintk(4, |
236 | KERN_INFO | 236 | KERN_INFO |
237 | "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n", | 237 | "%s: v4l_fbuffer_alloc() - V4L frame %d mem 0x%lx (bus: 0x%lx)\n", |
238 | ZR_DEVNAME(zr), i, (unsigned long) mem, | 238 | ZR_DEVNAME(zr), i, (unsigned long) mem, |
239 | virt_to_bus(mem)); | 239 | virt_to_bus(mem)); |
240 | } | 240 | } |
241 | 241 | ||
242 | fh->v4l_buffers.allocated = 1; | 242 | fh->v4l_buffers.allocated = 1; |
243 | 243 | ||
244 | return 0; | 244 | return 0; |
245 | } | 245 | } |
246 | 246 | ||
247 | /* free the V4L grab buffers */ | 247 | /* free the V4L grab buffers */ |
248 | static void | 248 | static void |
249 | v4l_fbuffer_free (struct file *file) | 249 | v4l_fbuffer_free (struct file *file) |
250 | { | 250 | { |
251 | struct zoran_fh *fh = file->private_data; | 251 | struct zoran_fh *fh = file->private_data; |
252 | struct zoran *zr = fh->zr; | 252 | struct zoran *zr = fh->zr; |
253 | int i, off; | 253 | int i, off; |
254 | unsigned char *mem; | 254 | unsigned char *mem; |
255 | 255 | ||
256 | dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr)); | 256 | dprintk(4, KERN_INFO "%s: v4l_fbuffer_free()\n", ZR_DEVNAME(zr)); |
257 | 257 | ||
258 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { | 258 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { |
259 | if (!fh->v4l_buffers.buffer[i].fbuffer) | 259 | if (!fh->v4l_buffers.buffer[i].fbuffer) |
260 | continue; | 260 | continue; |
261 | 261 | ||
262 | mem = fh->v4l_buffers.buffer[i].fbuffer; | 262 | mem = fh->v4l_buffers.buffer[i].fbuffer; |
263 | for (off = 0; off < fh->v4l_buffers.buffer_size; | 263 | for (off = 0; off < fh->v4l_buffers.buffer_size; |
264 | off += PAGE_SIZE) | 264 | off += PAGE_SIZE) |
265 | ClearPageReserved(virt_to_page(mem + off)); | 265 | ClearPageReserved(virt_to_page(mem + off)); |
266 | kfree((void *) fh->v4l_buffers.buffer[i].fbuffer); | 266 | kfree((void *) fh->v4l_buffers.buffer[i].fbuffer); |
267 | fh->v4l_buffers.buffer[i].fbuffer = NULL; | 267 | fh->v4l_buffers.buffer[i].fbuffer = NULL; |
268 | } | 268 | } |
269 | 269 | ||
270 | fh->v4l_buffers.allocated = 0; | 270 | fh->v4l_buffers.allocated = 0; |
271 | } | 271 | } |
272 | 272 | ||
273 | /* | 273 | /* |
274 | * Allocate the MJPEG grab buffers. | 274 | * Allocate the MJPEG grab buffers. |
275 | * | 275 | * |
276 | * If a Natoma chipset is present and this is a revision 1 zr36057, | 276 | * If a Natoma chipset is present and this is a revision 1 zr36057, |
277 | * each MJPEG buffer needs to be physically contiguous. | 277 | * each MJPEG buffer needs to be physically contiguous. |
278 | * (RJ: This statement is from Dave Perks' original driver, | 278 | * (RJ: This statement is from Dave Perks' original driver, |
279 | * I could never check it because I have a zr36067) | 279 | * I could never check it because I have a zr36067) |
280 | * | 280 | * |
281 | * RJ: The contents grab buffers needs never be accessed in the driver. | 281 | * RJ: The contents grab buffers needs never be accessed in the driver. |
282 | * Therefore there is no need to allocate them with vmalloc in order | 282 | * Therefore there is no need to allocate them with vmalloc in order |
283 | * to get a contiguous virtual memory space. | 283 | * to get a contiguous virtual memory space. |
284 | * I don't understand why many other drivers first allocate them with | 284 | * I don't understand why many other drivers first allocate them with |
285 | * vmalloc (which uses internally also get_zeroed_page, but delivers you | 285 | * vmalloc (which uses internally also get_zeroed_page, but delivers you |
286 | * virtual addresses) and then again have to make a lot of efforts | 286 | * virtual addresses) and then again have to make a lot of efforts |
287 | * to get the physical address. | 287 | * to get the physical address. |
288 | * | 288 | * |
289 | * Ben Capper: | 289 | * Ben Capper: |
290 | * On big-endian architectures (such as ppc) some extra steps | 290 | * On big-endian architectures (such as ppc) some extra steps |
291 | * are needed. When reading and writing to the stat_com array | 291 | * are needed. When reading and writing to the stat_com array |
292 | * and fragment buffers, the device expects to see little- | 292 | * and fragment buffers, the device expects to see little- |
293 | * endian values. The use of cpu_to_le32() and le32_to_cpu() | 293 | * endian values. The use of cpu_to_le32() and le32_to_cpu() |
294 | * in this function (and one or two others in zoran_device.c) | 294 | * in this function (and one or two others in zoran_device.c) |
295 | * ensure that these values are always stored in little-endian | 295 | * ensure that these values are always stored in little-endian |
296 | * form, regardless of architecture. The zr36057 does Very Bad | 296 | * form, regardless of architecture. The zr36057 does Very Bad |
297 | * Things on big endian architectures if the stat_com array | 297 | * Things on big endian architectures if the stat_com array |
298 | * and fragment buffers are not little-endian. | 298 | * and fragment buffers are not little-endian. |
299 | */ | 299 | */ |
300 | 300 | ||
301 | static int | 301 | static int |
302 | jpg_fbuffer_alloc (struct file *file) | 302 | jpg_fbuffer_alloc (struct file *file) |
303 | { | 303 | { |
304 | struct zoran_fh *fh = file->private_data; | 304 | struct zoran_fh *fh = file->private_data; |
305 | struct zoran *zr = fh->zr; | 305 | struct zoran *zr = fh->zr; |
306 | int i, j, off; | 306 | int i, j, off; |
307 | unsigned long mem; | 307 | unsigned long mem; |
308 | 308 | ||
309 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { | 309 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { |
310 | if (fh->jpg_buffers.buffer[i].frag_tab) | 310 | if (fh->jpg_buffers.buffer[i].frag_tab) |
311 | dprintk(2, | 311 | dprintk(2, |
312 | KERN_WARNING | 312 | KERN_WARNING |
313 | "%s: jpg_fbuffer_alloc() - buffer %d already allocated!?\n", | 313 | "%s: jpg_fbuffer_alloc() - buffer %d already allocated!?\n", |
314 | ZR_DEVNAME(zr), i); | 314 | ZR_DEVNAME(zr), i); |
315 | 315 | ||
316 | /* Allocate fragment table for this buffer */ | 316 | /* Allocate fragment table for this buffer */ |
317 | 317 | ||
318 | mem = get_zeroed_page(GFP_KERNEL); | 318 | mem = get_zeroed_page(GFP_KERNEL); |
319 | if (mem == 0) { | 319 | if (mem == 0) { |
320 | dprintk(1, | 320 | dprintk(1, |
321 | KERN_ERR | 321 | KERN_ERR |
322 | "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n", | 322 | "%s: jpg_fbuffer_alloc() - get_zeroed_page (frag_tab) failed for buffer %d\n", |
323 | ZR_DEVNAME(zr), i); | 323 | ZR_DEVNAME(zr), i); |
324 | jpg_fbuffer_free(file); | 324 | jpg_fbuffer_free(file); |
325 | return -ENOBUFS; | 325 | return -ENOBUFS; |
326 | } | 326 | } |
327 | fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem; | 327 | fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem; |
328 | fh->jpg_buffers.buffer[i].frag_tab_bus = | 328 | fh->jpg_buffers.buffer[i].frag_tab_bus = |
329 | virt_to_bus((void *) mem); | 329 | virt_to_bus((void *) mem); |
330 | 330 | ||
331 | //if (alloc_contig) { | 331 | //if (alloc_contig) { |
332 | if (fh->jpg_buffers.need_contiguous) { | 332 | if (fh->jpg_buffers.need_contiguous) { |
333 | mem = | 333 | mem = |
334 | (unsigned long) kmalloc(fh->jpg_buffers. | 334 | (unsigned long) kmalloc(fh->jpg_buffers. |
335 | buffer_size, | 335 | buffer_size, |
336 | GFP_KERNEL); | 336 | GFP_KERNEL); |
337 | if (mem == 0) { | 337 | if (mem == 0) { |
338 | dprintk(1, | 338 | dprintk(1, |
339 | KERN_ERR | 339 | KERN_ERR |
340 | "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n", | 340 | "%s: jpg_fbuffer_alloc() - kmalloc failed for buffer %d\n", |
341 | ZR_DEVNAME(zr), i); | 341 | ZR_DEVNAME(zr), i); |
342 | jpg_fbuffer_free(file); | 342 | jpg_fbuffer_free(file); |
343 | return -ENOBUFS; | 343 | return -ENOBUFS; |
344 | } | 344 | } |
345 | fh->jpg_buffers.buffer[i].frag_tab[0] = | 345 | fh->jpg_buffers.buffer[i].frag_tab[0] = |
346 | cpu_to_le32(virt_to_bus((void *) mem)); | 346 | cpu_to_le32(virt_to_bus((void *) mem)); |
347 | fh->jpg_buffers.buffer[i].frag_tab[1] = | 347 | fh->jpg_buffers.buffer[i].frag_tab[1] = |
348 | cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1); | 348 | cpu_to_le32(((fh->jpg_buffers.buffer_size / 4) << 1) | 1); |
349 | for (off = 0; off < fh->jpg_buffers.buffer_size; | 349 | for (off = 0; off < fh->jpg_buffers.buffer_size; |
350 | off += PAGE_SIZE) | 350 | off += PAGE_SIZE) |
351 | SetPageReserved(virt_to_page(mem + off)); | 351 | SetPageReserved(virt_to_page(mem + off)); |
352 | } else { | 352 | } else { |
353 | /* jpg_bufsize is already page aligned */ | 353 | /* jpg_bufsize is already page aligned */ |
354 | for (j = 0; | 354 | for (j = 0; |
355 | j < fh->jpg_buffers.buffer_size / PAGE_SIZE; | 355 | j < fh->jpg_buffers.buffer_size / PAGE_SIZE; |
356 | j++) { | 356 | j++) { |
357 | mem = get_zeroed_page(GFP_KERNEL); | 357 | mem = get_zeroed_page(GFP_KERNEL); |
358 | if (mem == 0) { | 358 | if (mem == 0) { |
359 | dprintk(1, | 359 | dprintk(1, |
360 | KERN_ERR | 360 | KERN_ERR |
361 | "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n", | 361 | "%s: jpg_fbuffer_alloc() - get_zeroed_page failed for buffer %d\n", |
362 | ZR_DEVNAME(zr), i); | 362 | ZR_DEVNAME(zr), i); |
363 | jpg_fbuffer_free(file); | 363 | jpg_fbuffer_free(file); |
364 | return -ENOBUFS; | 364 | return -ENOBUFS; |
365 | } | 365 | } |
366 | 366 | ||
367 | fh->jpg_buffers.buffer[i].frag_tab[2 * j] = | 367 | fh->jpg_buffers.buffer[i].frag_tab[2 * j] = |
368 | cpu_to_le32(virt_to_bus((void *) mem)); | 368 | cpu_to_le32(virt_to_bus((void *) mem)); |
369 | fh->jpg_buffers.buffer[i].frag_tab[2 * j + | 369 | fh->jpg_buffers.buffer[i].frag_tab[2 * j + |
370 | 1] = | 370 | 1] = |
371 | cpu_to_le32((PAGE_SIZE / 4) << 1); | 371 | cpu_to_le32((PAGE_SIZE / 4) << 1); |
372 | SetPageReserved(virt_to_page(mem)); | 372 | SetPageReserved(virt_to_page(mem)); |
373 | } | 373 | } |
374 | 374 | ||
375 | fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1); | 375 | fh->jpg_buffers.buffer[i].frag_tab[2 * j - 1] |= cpu_to_le32(1); |
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | dprintk(4, | 379 | dprintk(4, |
380 | KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n", | 380 | KERN_DEBUG "%s: jpg_fbuffer_alloc() - %d KB allocated\n", |
381 | ZR_DEVNAME(zr), | 381 | ZR_DEVNAME(zr), |
382 | (fh->jpg_buffers.num_buffers * | 382 | (fh->jpg_buffers.num_buffers * |
383 | fh->jpg_buffers.buffer_size) >> 10); | 383 | fh->jpg_buffers.buffer_size) >> 10); |
384 | 384 | ||
385 | fh->jpg_buffers.allocated = 1; | 385 | fh->jpg_buffers.allocated = 1; |
386 | 386 | ||
387 | return 0; | 387 | return 0; |
388 | } | 388 | } |
389 | 389 | ||
390 | /* free the MJPEG grab buffers */ | 390 | /* free the MJPEG grab buffers */ |
391 | static void | 391 | static void |
392 | jpg_fbuffer_free (struct file *file) | 392 | jpg_fbuffer_free (struct file *file) |
393 | { | 393 | { |
394 | struct zoran_fh *fh = file->private_data; | 394 | struct zoran_fh *fh = file->private_data; |
395 | struct zoran *zr = fh->zr; | 395 | struct zoran *zr = fh->zr; |
396 | int i, j, off; | 396 | int i, j, off; |
397 | unsigned char *mem; | 397 | unsigned char *mem; |
398 | __le32 frag_tab; | 398 | __le32 frag_tab; |
399 | 399 | ||
400 | dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr)); | 400 | dprintk(4, KERN_DEBUG "%s: jpg_fbuffer_free()\n", ZR_DEVNAME(zr)); |
401 | 401 | ||
402 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { | 402 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { |
403 | if (!fh->jpg_buffers.buffer[i].frag_tab) | 403 | if (!fh->jpg_buffers.buffer[i].frag_tab) |
404 | continue; | 404 | continue; |
405 | 405 | ||
406 | if (fh->jpg_buffers.need_contiguous) { | 406 | if (fh->jpg_buffers.need_contiguous) { |
407 | frag_tab = fh->jpg_buffers.buffer[i].frag_tab[0]; | 407 | frag_tab = fh->jpg_buffers.buffer[i].frag_tab[0]; |
408 | 408 | ||
409 | if (frag_tab) { | 409 | if (frag_tab) { |
410 | mem = (unsigned char *)bus_to_virt(le32_to_cpu(frag_tab)); | 410 | mem = (unsigned char *)bus_to_virt(le32_to_cpu(frag_tab)); |
411 | for (off = 0; off < fh->jpg_buffers.buffer_size; off += PAGE_SIZE) | 411 | for (off = 0; off < fh->jpg_buffers.buffer_size; off += PAGE_SIZE) |
412 | ClearPageReserved(virt_to_page(mem + off)); | 412 | ClearPageReserved(virt_to_page(mem + off)); |
413 | kfree(mem); | 413 | kfree(mem); |
414 | fh->jpg_buffers.buffer[i].frag_tab[0] = 0; | 414 | fh->jpg_buffers.buffer[i].frag_tab[0] = 0; |
415 | fh->jpg_buffers.buffer[i].frag_tab[1] = 0; | 415 | fh->jpg_buffers.buffer[i].frag_tab[1] = 0; |
416 | } | 416 | } |
417 | } else { | 417 | } else { |
418 | for (j = 0; j < fh->jpg_buffers.buffer_size / PAGE_SIZE; j++) { | 418 | for (j = 0; j < fh->jpg_buffers.buffer_size / PAGE_SIZE; j++) { |
419 | frag_tab = fh->jpg_buffers.buffer[i].frag_tab[2 * j]; | 419 | frag_tab = fh->jpg_buffers.buffer[i].frag_tab[2 * j]; |
420 | 420 | ||
421 | if (!frag_tab) | 421 | if (!frag_tab) |
422 | break; | 422 | break; |
423 | ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab)))); | 423 | ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab)))); |
424 | free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab))); | 424 | free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab))); |
425 | fh->jpg_buffers.buffer[i].frag_tab[2 * j] = 0; | 425 | fh->jpg_buffers.buffer[i].frag_tab[2 * j] = 0; |
426 | fh->jpg_buffers.buffer[i].frag_tab[2 * j + 1] = 0; | 426 | fh->jpg_buffers.buffer[i].frag_tab[2 * j + 1] = 0; |
427 | } | 427 | } |
428 | } | 428 | } |
429 | 429 | ||
430 | free_page((unsigned long)fh->jpg_buffers.buffer[i].frag_tab); | 430 | free_page((unsigned long)fh->jpg_buffers.buffer[i].frag_tab); |
431 | fh->jpg_buffers.buffer[i].frag_tab = NULL; | 431 | fh->jpg_buffers.buffer[i].frag_tab = NULL; |
432 | } | 432 | } |
433 | 433 | ||
434 | fh->jpg_buffers.allocated = 0; | 434 | fh->jpg_buffers.allocated = 0; |
435 | } | 435 | } |
436 | 436 | ||
437 | /* | 437 | /* |
438 | * V4L Buffer grabbing | 438 | * V4L Buffer grabbing |
439 | */ | 439 | */ |
440 | 440 | ||
441 | static int | 441 | static int |
442 | zoran_v4l_set_format (struct file *file, | 442 | zoran_v4l_set_format (struct file *file, |
443 | int width, | 443 | int width, |
444 | int height, | 444 | int height, |
445 | const struct zoran_format *format) | 445 | const struct zoran_format *format) |
446 | { | 446 | { |
447 | struct zoran_fh *fh = file->private_data; | 447 | struct zoran_fh *fh = file->private_data; |
448 | struct zoran *zr = fh->zr; | 448 | struct zoran *zr = fh->zr; |
449 | int bpp; | 449 | int bpp; |
450 | 450 | ||
451 | /* Check size and format of the grab wanted */ | 451 | /* Check size and format of the grab wanted */ |
452 | 452 | ||
453 | if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || | 453 | if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || |
454 | height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { | 454 | height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { |
455 | dprintk(1, | 455 | dprintk(1, |
456 | KERN_ERR | 456 | KERN_ERR |
457 | "%s: v4l_set_format() - wrong frame size (%dx%d)\n", | 457 | "%s: v4l_set_format() - wrong frame size (%dx%d)\n", |
458 | ZR_DEVNAME(zr), width, height); | 458 | ZR_DEVNAME(zr), width, height); |
459 | return -EINVAL; | 459 | return -EINVAL; |
460 | } | 460 | } |
461 | 461 | ||
462 | bpp = (format->depth + 7) / 8; | 462 | bpp = (format->depth + 7) / 8; |
463 | 463 | ||
464 | /* Check against available buffer size */ | 464 | /* Check against available buffer size */ |
465 | if (height * width * bpp > fh->v4l_buffers.buffer_size) { | 465 | if (height * width * bpp > fh->v4l_buffers.buffer_size) { |
466 | dprintk(1, | 466 | dprintk(1, |
467 | KERN_ERR | 467 | KERN_ERR |
468 | "%s: v4l_set_format() - video buffer size (%d kB) is too small\n", | 468 | "%s: v4l_set_format() - video buffer size (%d kB) is too small\n", |
469 | ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10); | 469 | ZR_DEVNAME(zr), fh->v4l_buffers.buffer_size >> 10); |
470 | return -EINVAL; | 470 | return -EINVAL; |
471 | } | 471 | } |
472 | 472 | ||
473 | /* The video front end needs 4-byte alinged line sizes */ | 473 | /* The video front end needs 4-byte alinged line sizes */ |
474 | 474 | ||
475 | if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { | 475 | if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { |
476 | dprintk(1, | 476 | dprintk(1, |
477 | KERN_ERR | 477 | KERN_ERR |
478 | "%s: v4l_set_format() - wrong frame alignment\n", | 478 | "%s: v4l_set_format() - wrong frame alignment\n", |
479 | ZR_DEVNAME(zr)); | 479 | ZR_DEVNAME(zr)); |
480 | return -EINVAL; | 480 | return -EINVAL; |
481 | } | 481 | } |
482 | 482 | ||
483 | fh->v4l_settings.width = width; | 483 | fh->v4l_settings.width = width; |
484 | fh->v4l_settings.height = height; | 484 | fh->v4l_settings.height = height; |
485 | fh->v4l_settings.format = format; | 485 | fh->v4l_settings.format = format; |
486 | fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width; | 486 | fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width; |
487 | 487 | ||
488 | return 0; | 488 | return 0; |
489 | } | 489 | } |
490 | 490 | ||
491 | static int | 491 | static int |
492 | zoran_v4l_queue_frame (struct file *file, | 492 | zoran_v4l_queue_frame (struct file *file, |
493 | int num) | 493 | int num) |
494 | { | 494 | { |
495 | struct zoran_fh *fh = file->private_data; | 495 | struct zoran_fh *fh = file->private_data; |
496 | struct zoran *zr = fh->zr; | 496 | struct zoran *zr = fh->zr; |
497 | unsigned long flags; | 497 | unsigned long flags; |
498 | int res = 0; | 498 | int res = 0; |
499 | 499 | ||
500 | if (!fh->v4l_buffers.allocated) { | 500 | if (!fh->v4l_buffers.allocated) { |
501 | dprintk(1, | 501 | dprintk(1, |
502 | KERN_ERR | 502 | KERN_ERR |
503 | "%s: v4l_queue_frame() - buffers not yet allocated\n", | 503 | "%s: v4l_queue_frame() - buffers not yet allocated\n", |
504 | ZR_DEVNAME(zr)); | 504 | ZR_DEVNAME(zr)); |
505 | res = -ENOMEM; | 505 | res = -ENOMEM; |
506 | } | 506 | } |
507 | 507 | ||
508 | /* No grabbing outside the buffer range! */ | 508 | /* No grabbing outside the buffer range! */ |
509 | if (num >= fh->v4l_buffers.num_buffers || num < 0) { | 509 | if (num >= fh->v4l_buffers.num_buffers || num < 0) { |
510 | dprintk(1, | 510 | dprintk(1, |
511 | KERN_ERR | 511 | KERN_ERR |
512 | "%s: v4l_queue_frame() - buffer %d is out of range\n", | 512 | "%s: v4l_queue_frame() - buffer %d is out of range\n", |
513 | ZR_DEVNAME(zr), num); | 513 | ZR_DEVNAME(zr), num); |
514 | res = -EINVAL; | 514 | res = -EINVAL; |
515 | } | 515 | } |
516 | 516 | ||
517 | spin_lock_irqsave(&zr->spinlock, flags); | 517 | spin_lock_irqsave(&zr->spinlock, flags); |
518 | 518 | ||
519 | if (fh->v4l_buffers.active == ZORAN_FREE) { | 519 | if (fh->v4l_buffers.active == ZORAN_FREE) { |
520 | if (zr->v4l_buffers.active == ZORAN_FREE) { | 520 | if (zr->v4l_buffers.active == ZORAN_FREE) { |
521 | zr->v4l_buffers = fh->v4l_buffers; | 521 | zr->v4l_buffers = fh->v4l_buffers; |
522 | fh->v4l_buffers.active = ZORAN_ACTIVE; | 522 | fh->v4l_buffers.active = ZORAN_ACTIVE; |
523 | } else { | 523 | } else { |
524 | dprintk(1, | 524 | dprintk(1, |
525 | KERN_ERR | 525 | KERN_ERR |
526 | "%s: v4l_queue_frame() - another session is already capturing\n", | 526 | "%s: v4l_queue_frame() - another session is already capturing\n", |
527 | ZR_DEVNAME(zr)); | 527 | ZR_DEVNAME(zr)); |
528 | res = -EBUSY; | 528 | res = -EBUSY; |
529 | } | 529 | } |
530 | } | 530 | } |
531 | 531 | ||
532 | /* make sure a grab isn't going on currently with this buffer */ | 532 | /* make sure a grab isn't going on currently with this buffer */ |
533 | if (!res) { | 533 | if (!res) { |
534 | switch (zr->v4l_buffers.buffer[num].state) { | 534 | switch (zr->v4l_buffers.buffer[num].state) { |
535 | default: | 535 | default: |
536 | case BUZ_STATE_PEND: | 536 | case BUZ_STATE_PEND: |
537 | if (zr->v4l_buffers.active == ZORAN_FREE) { | 537 | if (zr->v4l_buffers.active == ZORAN_FREE) { |
538 | fh->v4l_buffers.active = ZORAN_FREE; | 538 | fh->v4l_buffers.active = ZORAN_FREE; |
539 | zr->v4l_buffers.allocated = 0; | 539 | zr->v4l_buffers.allocated = 0; |
540 | } | 540 | } |
541 | res = -EBUSY; /* what are you doing? */ | 541 | res = -EBUSY; /* what are you doing? */ |
542 | break; | 542 | break; |
543 | case BUZ_STATE_DONE: | 543 | case BUZ_STATE_DONE: |
544 | dprintk(2, | 544 | dprintk(2, |
545 | KERN_WARNING | 545 | KERN_WARNING |
546 | "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n", | 546 | "%s: v4l_queue_frame() - queueing buffer %d in state DONE!?\n", |
547 | ZR_DEVNAME(zr), num); | 547 | ZR_DEVNAME(zr), num); |
548 | case BUZ_STATE_USER: | 548 | case BUZ_STATE_USER: |
549 | /* since there is at least one unused buffer there's room for at least | 549 | /* since there is at least one unused buffer there's room for at least |
550 | * one more pend[] entry */ | 550 | * one more pend[] entry */ |
551 | zr->v4l_pend[zr->v4l_pend_head++ & | 551 | zr->v4l_pend[zr->v4l_pend_head++ & |
552 | V4L_MASK_FRAME] = num; | 552 | V4L_MASK_FRAME] = num; |
553 | zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND; | 553 | zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND; |
554 | zr->v4l_buffers.buffer[num].bs.length = | 554 | zr->v4l_buffers.buffer[num].bs.length = |
555 | fh->v4l_settings.bytesperline * | 555 | fh->v4l_settings.bytesperline * |
556 | zr->v4l_settings.height; | 556 | zr->v4l_settings.height; |
557 | fh->v4l_buffers.buffer[num] = | 557 | fh->v4l_buffers.buffer[num] = |
558 | zr->v4l_buffers.buffer[num]; | 558 | zr->v4l_buffers.buffer[num]; |
559 | break; | 559 | break; |
560 | } | 560 | } |
561 | } | 561 | } |
562 | 562 | ||
563 | spin_unlock_irqrestore(&zr->spinlock, flags); | 563 | spin_unlock_irqrestore(&zr->spinlock, flags); |
564 | 564 | ||
565 | if (!res && zr->v4l_buffers.active == ZORAN_FREE) | 565 | if (!res && zr->v4l_buffers.active == ZORAN_FREE) |
566 | zr->v4l_buffers.active = fh->v4l_buffers.active; | 566 | zr->v4l_buffers.active = fh->v4l_buffers.active; |
567 | 567 | ||
568 | return res; | 568 | return res; |
569 | } | 569 | } |
570 | 570 | ||
571 | /* | 571 | /* |
572 | * Sync on a V4L buffer | 572 | * Sync on a V4L buffer |
573 | */ | 573 | */ |
574 | 574 | ||
575 | static int | 575 | static int |
576 | v4l_sync (struct file *file, | 576 | v4l_sync (struct file *file, |
577 | int frame) | 577 | int frame) |
578 | { | 578 | { |
579 | struct zoran_fh *fh = file->private_data; | 579 | struct zoran_fh *fh = file->private_data; |
580 | struct zoran *zr = fh->zr; | 580 | struct zoran *zr = fh->zr; |
581 | unsigned long flags; | 581 | unsigned long flags; |
582 | 582 | ||
583 | if (fh->v4l_buffers.active == ZORAN_FREE) { | 583 | if (fh->v4l_buffers.active == ZORAN_FREE) { |
584 | dprintk(1, | 584 | dprintk(1, |
585 | KERN_ERR | 585 | KERN_ERR |
586 | "%s: v4l_sync() - no grab active for this session\n", | 586 | "%s: v4l_sync() - no grab active for this session\n", |
587 | ZR_DEVNAME(zr)); | 587 | ZR_DEVNAME(zr)); |
588 | return -EINVAL; | 588 | return -EINVAL; |
589 | } | 589 | } |
590 | 590 | ||
591 | /* check passed-in frame number */ | 591 | /* check passed-in frame number */ |
592 | if (frame >= fh->v4l_buffers.num_buffers || frame < 0) { | 592 | if (frame >= fh->v4l_buffers.num_buffers || frame < 0) { |
593 | dprintk(1, | 593 | dprintk(1, |
594 | KERN_ERR "%s: v4l_sync() - frame %d is invalid\n", | 594 | KERN_ERR "%s: v4l_sync() - frame %d is invalid\n", |
595 | ZR_DEVNAME(zr), frame); | 595 | ZR_DEVNAME(zr), frame); |
596 | return -EINVAL; | 596 | return -EINVAL; |
597 | } | 597 | } |
598 | 598 | ||
599 | /* Check if is buffer was queued at all */ | 599 | /* Check if is buffer was queued at all */ |
600 | if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) { | 600 | if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) { |
601 | dprintk(1, | 601 | dprintk(1, |
602 | KERN_ERR | 602 | KERN_ERR |
603 | "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n", | 603 | "%s: v4l_sync() - attempt to sync on a buffer which was not queued?\n", |
604 | ZR_DEVNAME(zr)); | 604 | ZR_DEVNAME(zr)); |
605 | return -EPROTO; | 605 | return -EPROTO; |
606 | } | 606 | } |
607 | 607 | ||
608 | /* wait on this buffer to get ready */ | 608 | /* wait on this buffer to get ready */ |
609 | if (!wait_event_interruptible_timeout(zr->v4l_capq, | 609 | if (!wait_event_interruptible_timeout(zr->v4l_capq, |
610 | (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), | 610 | (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), |
611 | 10*HZ)) | 611 | 10*HZ)) |
612 | return -ETIME; | 612 | return -ETIME; |
613 | if (signal_pending(current)) | 613 | if (signal_pending(current)) |
614 | return -ERESTARTSYS; | 614 | return -ERESTARTSYS; |
615 | 615 | ||
616 | /* buffer should now be in BUZ_STATE_DONE */ | 616 | /* buffer should now be in BUZ_STATE_DONE */ |
617 | if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) | 617 | if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) |
618 | dprintk(2, | 618 | dprintk(2, |
619 | KERN_ERR "%s: v4l_sync() - internal state error\n", | 619 | KERN_ERR "%s: v4l_sync() - internal state error\n", |
620 | ZR_DEVNAME(zr)); | 620 | ZR_DEVNAME(zr)); |
621 | 621 | ||
622 | zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER; | 622 | zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER; |
623 | fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame]; | 623 | fh->v4l_buffers.buffer[frame] = zr->v4l_buffers.buffer[frame]; |
624 | 624 | ||
625 | spin_lock_irqsave(&zr->spinlock, flags); | 625 | spin_lock_irqsave(&zr->spinlock, flags); |
626 | 626 | ||
627 | /* Check if streaming capture has finished */ | 627 | /* Check if streaming capture has finished */ |
628 | if (zr->v4l_pend_tail == zr->v4l_pend_head) { | 628 | if (zr->v4l_pend_tail == zr->v4l_pend_head) { |
629 | zr36057_set_memgrab(zr, 0); | 629 | zr36057_set_memgrab(zr, 0); |
630 | if (zr->v4l_buffers.active == ZORAN_ACTIVE) { | 630 | if (zr->v4l_buffers.active == ZORAN_ACTIVE) { |
631 | fh->v4l_buffers.active = zr->v4l_buffers.active = | 631 | fh->v4l_buffers.active = zr->v4l_buffers.active = |
632 | ZORAN_FREE; | 632 | ZORAN_FREE; |
633 | zr->v4l_buffers.allocated = 0; | 633 | zr->v4l_buffers.allocated = 0; |
634 | } | 634 | } |
635 | } | 635 | } |
636 | 636 | ||
637 | spin_unlock_irqrestore(&zr->spinlock, flags); | 637 | spin_unlock_irqrestore(&zr->spinlock, flags); |
638 | 638 | ||
639 | return 0; | 639 | return 0; |
640 | } | 640 | } |
641 | 641 | ||
642 | /* | 642 | /* |
643 | * Queue a MJPEG buffer for capture/playback | 643 | * Queue a MJPEG buffer for capture/playback |
644 | */ | 644 | */ |
645 | 645 | ||
646 | static int | 646 | static int |
647 | zoran_jpg_queue_frame (struct file *file, | 647 | zoran_jpg_queue_frame (struct file *file, |
648 | int num, | 648 | int num, |
649 | enum zoran_codec_mode mode) | 649 | enum zoran_codec_mode mode) |
650 | { | 650 | { |
651 | struct zoran_fh *fh = file->private_data; | 651 | struct zoran_fh *fh = file->private_data; |
652 | struct zoran *zr = fh->zr; | 652 | struct zoran *zr = fh->zr; |
653 | unsigned long flags; | 653 | unsigned long flags; |
654 | int res = 0; | 654 | int res = 0; |
655 | 655 | ||
656 | /* Check if buffers are allocated */ | 656 | /* Check if buffers are allocated */ |
657 | if (!fh->jpg_buffers.allocated) { | 657 | if (!fh->jpg_buffers.allocated) { |
658 | dprintk(1, | 658 | dprintk(1, |
659 | KERN_ERR | 659 | KERN_ERR |
660 | "%s: jpg_queue_frame() - buffers not yet allocated\n", | 660 | "%s: jpg_queue_frame() - buffers not yet allocated\n", |
661 | ZR_DEVNAME(zr)); | 661 | ZR_DEVNAME(zr)); |
662 | return -ENOMEM; | 662 | return -ENOMEM; |
663 | } | 663 | } |
664 | 664 | ||
665 | /* No grabbing outside the buffer range! */ | 665 | /* No grabbing outside the buffer range! */ |
666 | if (num >= fh->jpg_buffers.num_buffers || num < 0) { | 666 | if (num >= fh->jpg_buffers.num_buffers || num < 0) { |
667 | dprintk(1, | 667 | dprintk(1, |
668 | KERN_ERR | 668 | KERN_ERR |
669 | "%s: jpg_queue_frame() - buffer %d out of range\n", | 669 | "%s: jpg_queue_frame() - buffer %d out of range\n", |
670 | ZR_DEVNAME(zr), num); | 670 | ZR_DEVNAME(zr), num); |
671 | return -EINVAL; | 671 | return -EINVAL; |
672 | } | 672 | } |
673 | 673 | ||
674 | /* what is the codec mode right now? */ | 674 | /* what is the codec mode right now? */ |
675 | if (zr->codec_mode == BUZ_MODE_IDLE) { | 675 | if (zr->codec_mode == BUZ_MODE_IDLE) { |
676 | zr->jpg_settings = fh->jpg_settings; | 676 | zr->jpg_settings = fh->jpg_settings; |
677 | } else if (zr->codec_mode != mode) { | 677 | } else if (zr->codec_mode != mode) { |
678 | /* wrong codec mode active - invalid */ | 678 | /* wrong codec mode active - invalid */ |
679 | dprintk(1, | 679 | dprintk(1, |
680 | KERN_ERR | 680 | KERN_ERR |
681 | "%s: jpg_queue_frame() - codec in wrong mode\n", | 681 | "%s: jpg_queue_frame() - codec in wrong mode\n", |
682 | ZR_DEVNAME(zr)); | 682 | ZR_DEVNAME(zr)); |
683 | return -EINVAL; | 683 | return -EINVAL; |
684 | } | 684 | } |
685 | 685 | ||
686 | if (fh->jpg_buffers.active == ZORAN_FREE) { | 686 | if (fh->jpg_buffers.active == ZORAN_FREE) { |
687 | if (zr->jpg_buffers.active == ZORAN_FREE) { | 687 | if (zr->jpg_buffers.active == ZORAN_FREE) { |
688 | zr->jpg_buffers = fh->jpg_buffers; | 688 | zr->jpg_buffers = fh->jpg_buffers; |
689 | fh->jpg_buffers.active = ZORAN_ACTIVE; | 689 | fh->jpg_buffers.active = ZORAN_ACTIVE; |
690 | } else { | 690 | } else { |
691 | dprintk(1, | 691 | dprintk(1, |
692 | KERN_ERR | 692 | KERN_ERR |
693 | "%s: jpg_queue_frame() - another session is already capturing\n", | 693 | "%s: jpg_queue_frame() - another session is already capturing\n", |
694 | ZR_DEVNAME(zr)); | 694 | ZR_DEVNAME(zr)); |
695 | res = -EBUSY; | 695 | res = -EBUSY; |
696 | } | 696 | } |
697 | } | 697 | } |
698 | 698 | ||
699 | if (!res && zr->codec_mode == BUZ_MODE_IDLE) { | 699 | if (!res && zr->codec_mode == BUZ_MODE_IDLE) { |
700 | /* Ok load up the jpeg codec */ | 700 | /* Ok load up the jpeg codec */ |
701 | zr36057_enable_jpg(zr, mode); | 701 | zr36057_enable_jpg(zr, mode); |
702 | } | 702 | } |
703 | 703 | ||
704 | spin_lock_irqsave(&zr->spinlock, flags); | 704 | spin_lock_irqsave(&zr->spinlock, flags); |
705 | 705 | ||
706 | if (!res) { | 706 | if (!res) { |
707 | switch (zr->jpg_buffers.buffer[num].state) { | 707 | switch (zr->jpg_buffers.buffer[num].state) { |
708 | case BUZ_STATE_DONE: | 708 | case BUZ_STATE_DONE: |
709 | dprintk(2, | 709 | dprintk(2, |
710 | KERN_WARNING | 710 | KERN_WARNING |
711 | "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n", | 711 | "%s: jpg_queue_frame() - queing frame in BUZ_STATE_DONE state!?\n", |
712 | ZR_DEVNAME(zr)); | 712 | ZR_DEVNAME(zr)); |
713 | case BUZ_STATE_USER: | 713 | case BUZ_STATE_USER: |
714 | /* since there is at least one unused buffer there's room for at | 714 | /* since there is at least one unused buffer there's room for at |
715 | *least one more pend[] entry */ | 715 | *least one more pend[] entry */ |
716 | zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = | 716 | zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = |
717 | num; | 717 | num; |
718 | zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND; | 718 | zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND; |
719 | fh->jpg_buffers.buffer[num] = | 719 | fh->jpg_buffers.buffer[num] = |
720 | zr->jpg_buffers.buffer[num]; | 720 | zr->jpg_buffers.buffer[num]; |
721 | zoran_feed_stat_com(zr); | 721 | zoran_feed_stat_com(zr); |
722 | break; | 722 | break; |
723 | default: | 723 | default: |
724 | case BUZ_STATE_DMA: | 724 | case BUZ_STATE_DMA: |
725 | case BUZ_STATE_PEND: | 725 | case BUZ_STATE_PEND: |
726 | if (zr->jpg_buffers.active == ZORAN_FREE) { | 726 | if (zr->jpg_buffers.active == ZORAN_FREE) { |
727 | fh->jpg_buffers.active = ZORAN_FREE; | 727 | fh->jpg_buffers.active = ZORAN_FREE; |
728 | zr->jpg_buffers.allocated = 0; | 728 | zr->jpg_buffers.allocated = 0; |
729 | } | 729 | } |
730 | res = -EBUSY; /* what are you doing? */ | 730 | res = -EBUSY; /* what are you doing? */ |
731 | break; | 731 | break; |
732 | } | 732 | } |
733 | } | 733 | } |
734 | 734 | ||
735 | spin_unlock_irqrestore(&zr->spinlock, flags); | 735 | spin_unlock_irqrestore(&zr->spinlock, flags); |
736 | 736 | ||
737 | if (!res && zr->jpg_buffers.active == ZORAN_FREE) { | 737 | if (!res && zr->jpg_buffers.active == ZORAN_FREE) { |
738 | zr->jpg_buffers.active = fh->jpg_buffers.active; | 738 | zr->jpg_buffers.active = fh->jpg_buffers.active; |
739 | } | 739 | } |
740 | 740 | ||
741 | return res; | 741 | return res; |
742 | } | 742 | } |
743 | 743 | ||
744 | static int | 744 | static int |
745 | jpg_qbuf (struct file *file, | 745 | jpg_qbuf (struct file *file, |
746 | int frame, | 746 | int frame, |
747 | enum zoran_codec_mode mode) | 747 | enum zoran_codec_mode mode) |
748 | { | 748 | { |
749 | struct zoran_fh *fh = file->private_data; | 749 | struct zoran_fh *fh = file->private_data; |
750 | struct zoran *zr = fh->zr; | 750 | struct zoran *zr = fh->zr; |
751 | int res = 0; | 751 | int res = 0; |
752 | 752 | ||
753 | /* Does the user want to stop streaming? */ | 753 | /* Does the user want to stop streaming? */ |
754 | if (frame < 0) { | 754 | if (frame < 0) { |
755 | if (zr->codec_mode == mode) { | 755 | if (zr->codec_mode == mode) { |
756 | if (fh->jpg_buffers.active == ZORAN_FREE) { | 756 | if (fh->jpg_buffers.active == ZORAN_FREE) { |
757 | dprintk(1, | 757 | dprintk(1, |
758 | KERN_ERR | 758 | KERN_ERR |
759 | "%s: jpg_qbuf(-1) - session not active\n", | 759 | "%s: jpg_qbuf(-1) - session not active\n", |
760 | ZR_DEVNAME(zr)); | 760 | ZR_DEVNAME(zr)); |
761 | return -EINVAL; | 761 | return -EINVAL; |
762 | } | 762 | } |
763 | fh->jpg_buffers.active = zr->jpg_buffers.active = | 763 | fh->jpg_buffers.active = zr->jpg_buffers.active = |
764 | ZORAN_FREE; | 764 | ZORAN_FREE; |
765 | zr->jpg_buffers.allocated = 0; | 765 | zr->jpg_buffers.allocated = 0; |
766 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); | 766 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); |
767 | return 0; | 767 | return 0; |
768 | } else { | 768 | } else { |
769 | dprintk(1, | 769 | dprintk(1, |
770 | KERN_ERR | 770 | KERN_ERR |
771 | "%s: jpg_qbuf() - stop streaming but not in streaming mode\n", | 771 | "%s: jpg_qbuf() - stop streaming but not in streaming mode\n", |
772 | ZR_DEVNAME(zr)); | 772 | ZR_DEVNAME(zr)); |
773 | return -EINVAL; | 773 | return -EINVAL; |
774 | } | 774 | } |
775 | } | 775 | } |
776 | 776 | ||
777 | if ((res = zoran_jpg_queue_frame(file, frame, mode))) | 777 | if ((res = zoran_jpg_queue_frame(file, frame, mode))) |
778 | return res; | 778 | return res; |
779 | 779 | ||
780 | /* Start the jpeg codec when the first frame is queued */ | 780 | /* Start the jpeg codec when the first frame is queued */ |
781 | if (!res && zr->jpg_que_head == 1) | 781 | if (!res && zr->jpg_que_head == 1) |
782 | jpeg_start(zr); | 782 | jpeg_start(zr); |
783 | 783 | ||
784 | return res; | 784 | return res; |
785 | } | 785 | } |
786 | 786 | ||
787 | /* | 787 | /* |
788 | * Sync on a MJPEG buffer | 788 | * Sync on a MJPEG buffer |
789 | */ | 789 | */ |
790 | 790 | ||
791 | static int | 791 | static int |
792 | jpg_sync (struct file *file, | 792 | jpg_sync (struct file *file, |
793 | struct zoran_sync *bs) | 793 | struct zoran_sync *bs) |
794 | { | 794 | { |
795 | struct zoran_fh *fh = file->private_data; | 795 | struct zoran_fh *fh = file->private_data; |
796 | struct zoran *zr = fh->zr; | 796 | struct zoran *zr = fh->zr; |
797 | unsigned long flags; | 797 | unsigned long flags; |
798 | int frame; | 798 | int frame; |
799 | 799 | ||
800 | if (fh->jpg_buffers.active == ZORAN_FREE) { | 800 | if (fh->jpg_buffers.active == ZORAN_FREE) { |
801 | dprintk(1, | 801 | dprintk(1, |
802 | KERN_ERR | 802 | KERN_ERR |
803 | "%s: jpg_sync() - capture is not currently active\n", | 803 | "%s: jpg_sync() - capture is not currently active\n", |
804 | ZR_DEVNAME(zr)); | 804 | ZR_DEVNAME(zr)); |
805 | return -EINVAL; | 805 | return -EINVAL; |
806 | } | 806 | } |
807 | if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && | 807 | if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && |
808 | zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { | 808 | zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { |
809 | dprintk(1, | 809 | dprintk(1, |
810 | KERN_ERR | 810 | KERN_ERR |
811 | "%s: jpg_sync() - codec not in streaming mode\n", | 811 | "%s: jpg_sync() - codec not in streaming mode\n", |
812 | ZR_DEVNAME(zr)); | 812 | ZR_DEVNAME(zr)); |
813 | return -EINVAL; | 813 | return -EINVAL; |
814 | } | 814 | } |
815 | if (!wait_event_interruptible_timeout(zr->jpg_capq, | 815 | if (!wait_event_interruptible_timeout(zr->jpg_capq, |
816 | (zr->jpg_que_tail != zr->jpg_dma_tail || | 816 | (zr->jpg_que_tail != zr->jpg_dma_tail || |
817 | zr->jpg_dma_tail == zr->jpg_dma_head), | 817 | zr->jpg_dma_tail == zr->jpg_dma_head), |
818 | 10*HZ)) { | 818 | 10*HZ)) { |
819 | int isr; | 819 | int isr; |
820 | 820 | ||
821 | btand(~ZR36057_JMC_Go_en, ZR36057_JMC); | 821 | btand(~ZR36057_JMC_Go_en, ZR36057_JMC); |
822 | udelay(1); | 822 | udelay(1); |
823 | zr->codec->control(zr->codec, CODEC_G_STATUS, | 823 | zr->codec->control(zr->codec, CODEC_G_STATUS, |
824 | sizeof(isr), &isr); | 824 | sizeof(isr), &isr); |
825 | dprintk(1, | 825 | dprintk(1, |
826 | KERN_ERR | 826 | KERN_ERR |
827 | "%s: jpg_sync() - timeout: codec isr=0x%02x\n", | 827 | "%s: jpg_sync() - timeout: codec isr=0x%02x\n", |
828 | ZR_DEVNAME(zr), isr); | 828 | ZR_DEVNAME(zr), isr); |
829 | 829 | ||
830 | return -ETIME; | 830 | return -ETIME; |
831 | 831 | ||
832 | } | 832 | } |
833 | if (signal_pending(current)) | 833 | if (signal_pending(current)) |
834 | return -ERESTARTSYS; | 834 | return -ERESTARTSYS; |
835 | 835 | ||
836 | spin_lock_irqsave(&zr->spinlock, flags); | 836 | spin_lock_irqsave(&zr->spinlock, flags); |
837 | 837 | ||
838 | if (zr->jpg_dma_tail != zr->jpg_dma_head) | 838 | if (zr->jpg_dma_tail != zr->jpg_dma_head) |
839 | frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; | 839 | frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; |
840 | else | 840 | else |
841 | frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; | 841 | frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; |
842 | 842 | ||
843 | /* buffer should now be in BUZ_STATE_DONE */ | 843 | /* buffer should now be in BUZ_STATE_DONE */ |
844 | if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) | 844 | if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) |
845 | dprintk(2, | 845 | dprintk(2, |
846 | KERN_ERR "%s: jpg_sync() - internal state error\n", | 846 | KERN_ERR "%s: jpg_sync() - internal state error\n", |
847 | ZR_DEVNAME(zr)); | 847 | ZR_DEVNAME(zr)); |
848 | 848 | ||
849 | *bs = zr->jpg_buffers.buffer[frame].bs; | 849 | *bs = zr->jpg_buffers.buffer[frame].bs; |
850 | bs->frame = frame; | 850 | bs->frame = frame; |
851 | zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER; | 851 | zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER; |
852 | fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame]; | 852 | fh->jpg_buffers.buffer[frame] = zr->jpg_buffers.buffer[frame]; |
853 | 853 | ||
854 | spin_unlock_irqrestore(&zr->spinlock, flags); | 854 | spin_unlock_irqrestore(&zr->spinlock, flags); |
855 | 855 | ||
856 | return 0; | 856 | return 0; |
857 | } | 857 | } |
858 | 858 | ||
859 | static void | 859 | static void |
860 | zoran_open_init_session (struct file *file) | 860 | zoran_open_init_session (struct file *file) |
861 | { | 861 | { |
862 | int i; | 862 | int i; |
863 | struct zoran_fh *fh = file->private_data; | 863 | struct zoran_fh *fh = file->private_data; |
864 | struct zoran *zr = fh->zr; | 864 | struct zoran *zr = fh->zr; |
865 | 865 | ||
866 | /* Per default, map the V4L Buffers */ | 866 | /* Per default, map the V4L Buffers */ |
867 | fh->map_mode = ZORAN_MAP_MODE_RAW; | 867 | fh->map_mode = ZORAN_MAP_MODE_RAW; |
868 | 868 | ||
869 | /* take over the card's current settings */ | 869 | /* take over the card's current settings */ |
870 | fh->overlay_settings = zr->overlay_settings; | 870 | fh->overlay_settings = zr->overlay_settings; |
871 | fh->overlay_settings.is_set = 0; | 871 | fh->overlay_settings.is_set = 0; |
872 | fh->overlay_settings.format = zr->overlay_settings.format; | 872 | fh->overlay_settings.format = zr->overlay_settings.format; |
873 | fh->overlay_active = ZORAN_FREE; | 873 | fh->overlay_active = ZORAN_FREE; |
874 | 874 | ||
875 | /* v4l settings */ | 875 | /* v4l settings */ |
876 | fh->v4l_settings = zr->v4l_settings; | 876 | fh->v4l_settings = zr->v4l_settings; |
877 | 877 | ||
878 | /* v4l_buffers */ | 878 | /* v4l_buffers */ |
879 | memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct)); | 879 | memset(&fh->v4l_buffers, 0, sizeof(struct zoran_v4l_struct)); |
880 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 880 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
881 | fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ | 881 | fh->v4l_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ |
882 | fh->v4l_buffers.buffer[i].bs.frame = i; | 882 | fh->v4l_buffers.buffer[i].bs.frame = i; |
883 | } | 883 | } |
884 | fh->v4l_buffers.allocated = 0; | 884 | fh->v4l_buffers.allocated = 0; |
885 | fh->v4l_buffers.active = ZORAN_FREE; | 885 | fh->v4l_buffers.active = ZORAN_FREE; |
886 | fh->v4l_buffers.buffer_size = v4l_bufsize; | 886 | fh->v4l_buffers.buffer_size = v4l_bufsize; |
887 | fh->v4l_buffers.num_buffers = v4l_nbufs; | 887 | fh->v4l_buffers.num_buffers = v4l_nbufs; |
888 | 888 | ||
889 | /* jpg settings */ | 889 | /* jpg settings */ |
890 | fh->jpg_settings = zr->jpg_settings; | 890 | fh->jpg_settings = zr->jpg_settings; |
891 | 891 | ||
892 | /* jpg_buffers */ | 892 | /* jpg_buffers */ |
893 | memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct)); | 893 | memset(&fh->jpg_buffers, 0, sizeof(struct zoran_jpg_struct)); |
894 | for (i = 0; i < BUZ_MAX_FRAME; i++) { | 894 | for (i = 0; i < BUZ_MAX_FRAME; i++) { |
895 | fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ | 895 | fh->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ |
896 | fh->jpg_buffers.buffer[i].bs.frame = i; | 896 | fh->jpg_buffers.buffer[i].bs.frame = i; |
897 | } | 897 | } |
898 | fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous; | 898 | fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous; |
899 | fh->jpg_buffers.allocated = 0; | 899 | fh->jpg_buffers.allocated = 0; |
900 | fh->jpg_buffers.active = ZORAN_FREE; | 900 | fh->jpg_buffers.active = ZORAN_FREE; |
901 | fh->jpg_buffers.buffer_size = jpg_bufsize; | 901 | fh->jpg_buffers.buffer_size = jpg_bufsize; |
902 | fh->jpg_buffers.num_buffers = jpg_nbufs; | 902 | fh->jpg_buffers.num_buffers = jpg_nbufs; |
903 | } | 903 | } |
904 | 904 | ||
905 | static void | 905 | static void |
906 | zoran_close_end_session (struct file *file) | 906 | zoran_close_end_session (struct file *file) |
907 | { | 907 | { |
908 | struct zoran_fh *fh = file->private_data; | 908 | struct zoran_fh *fh = file->private_data; |
909 | struct zoran *zr = fh->zr; | 909 | struct zoran *zr = fh->zr; |
910 | 910 | ||
911 | /* overlay */ | 911 | /* overlay */ |
912 | if (fh->overlay_active != ZORAN_FREE) { | 912 | if (fh->overlay_active != ZORAN_FREE) { |
913 | fh->overlay_active = zr->overlay_active = ZORAN_FREE; | 913 | fh->overlay_active = zr->overlay_active = ZORAN_FREE; |
914 | zr->v4l_overlay_active = 0; | 914 | zr->v4l_overlay_active = 0; |
915 | if (!zr->v4l_memgrab_active) | 915 | if (!zr->v4l_memgrab_active) |
916 | zr36057_overlay(zr, 0); | 916 | zr36057_overlay(zr, 0); |
917 | zr->overlay_mask = NULL; | 917 | zr->overlay_mask = NULL; |
918 | } | 918 | } |
919 | 919 | ||
920 | /* v4l capture */ | 920 | /* v4l capture */ |
921 | if (fh->v4l_buffers.active != ZORAN_FREE) { | 921 | if (fh->v4l_buffers.active != ZORAN_FREE) { |
922 | unsigned long flags; | 922 | unsigned long flags; |
923 | 923 | ||
924 | spin_lock_irqsave(&zr->spinlock, flags); | 924 | spin_lock_irqsave(&zr->spinlock, flags); |
925 | zr36057_set_memgrab(zr, 0); | 925 | zr36057_set_memgrab(zr, 0); |
926 | zr->v4l_buffers.allocated = 0; | 926 | zr->v4l_buffers.allocated = 0; |
927 | zr->v4l_buffers.active = fh->v4l_buffers.active = | 927 | zr->v4l_buffers.active = fh->v4l_buffers.active = |
928 | ZORAN_FREE; | 928 | ZORAN_FREE; |
929 | spin_unlock_irqrestore(&zr->spinlock, flags); | 929 | spin_unlock_irqrestore(&zr->spinlock, flags); |
930 | } | 930 | } |
931 | 931 | ||
932 | /* v4l buffers */ | 932 | /* v4l buffers */ |
933 | if (fh->v4l_buffers.allocated) | 933 | if (fh->v4l_buffers.allocated) |
934 | v4l_fbuffer_free(file); | 934 | v4l_fbuffer_free(file); |
935 | 935 | ||
936 | /* jpg capture */ | 936 | /* jpg capture */ |
937 | if (fh->jpg_buffers.active != ZORAN_FREE) { | 937 | if (fh->jpg_buffers.active != ZORAN_FREE) { |
938 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); | 938 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); |
939 | zr->jpg_buffers.allocated = 0; | 939 | zr->jpg_buffers.allocated = 0; |
940 | zr->jpg_buffers.active = fh->jpg_buffers.active = | 940 | zr->jpg_buffers.active = fh->jpg_buffers.active = |
941 | ZORAN_FREE; | 941 | ZORAN_FREE; |
942 | } | 942 | } |
943 | 943 | ||
944 | /* jpg buffers */ | 944 | /* jpg buffers */ |
945 | if (fh->jpg_buffers.allocated) | 945 | if (fh->jpg_buffers.allocated) |
946 | jpg_fbuffer_free(file); | 946 | jpg_fbuffer_free(file); |
947 | } | 947 | } |
948 | 948 | ||
949 | /* | 949 | /* |
950 | * Open a zoran card. Right now the flags stuff is just playing | 950 | * Open a zoran card. Right now the flags stuff is just playing |
951 | */ | 951 | */ |
952 | 952 | ||
953 | static int zoran_open(struct file *file) | 953 | static int zoran_open(struct file *file) |
954 | { | 954 | { |
955 | struct zoran *zr = video_drvdata(file); | 955 | struct zoran *zr = video_drvdata(file); |
956 | struct zoran_fh *fh; | 956 | struct zoran_fh *fh; |
957 | int res, first_open = 0; | 957 | int res, first_open = 0; |
958 | 958 | ||
959 | dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n", | 959 | dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n", |
960 | ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1); | 960 | ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1); |
961 | 961 | ||
962 | lock_kernel(); | 962 | lock_kernel(); |
963 | 963 | ||
964 | if (zr->user >= 2048) { | 964 | if (zr->user >= 2048) { |
965 | dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", | 965 | dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", |
966 | ZR_DEVNAME(zr), zr->user); | 966 | ZR_DEVNAME(zr), zr->user); |
967 | res = -EBUSY; | 967 | res = -EBUSY; |
968 | goto fail_unlock; | 968 | goto fail_unlock; |
969 | } | 969 | } |
970 | 970 | ||
971 | /* now, create the open()-specific file_ops struct */ | 971 | /* now, create the open()-specific file_ops struct */ |
972 | fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL); | 972 | fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL); |
973 | if (!fh) { | 973 | if (!fh) { |
974 | dprintk(1, | 974 | dprintk(1, |
975 | KERN_ERR | 975 | KERN_ERR |
976 | "%s: zoran_open() - allocation of zoran_fh failed\n", | 976 | "%s: zoran_open() - allocation of zoran_fh failed\n", |
977 | ZR_DEVNAME(zr)); | 977 | ZR_DEVNAME(zr)); |
978 | res = -ENOMEM; | 978 | res = -ENOMEM; |
979 | goto fail_unlock; | 979 | goto fail_unlock; |
980 | } | 980 | } |
981 | /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows | 981 | /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows |
982 | * on norm-change! */ | 982 | * on norm-change! */ |
983 | fh->overlay_mask = | 983 | fh->overlay_mask = |
984 | kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL); | 984 | kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL); |
985 | if (!fh->overlay_mask) { | 985 | if (!fh->overlay_mask) { |
986 | dprintk(1, | 986 | dprintk(1, |
987 | KERN_ERR | 987 | KERN_ERR |
988 | "%s: zoran_open() - allocation of overlay_mask failed\n", | 988 | "%s: zoran_open() - allocation of overlay_mask failed\n", |
989 | ZR_DEVNAME(zr)); | 989 | ZR_DEVNAME(zr)); |
990 | res = -ENOMEM; | 990 | res = -ENOMEM; |
991 | goto fail_fh; | 991 | goto fail_fh; |
992 | } | 992 | } |
993 | 993 | ||
994 | if (zr->user++ == 0) | 994 | if (zr->user++ == 0) |
995 | first_open = 1; | 995 | first_open = 1; |
996 | 996 | ||
997 | /*mutex_unlock(&zr->resource_lock);*/ | 997 | /*mutex_unlock(&zr->resource_lock);*/ |
998 | 998 | ||
999 | /* default setup - TODO: look at flags */ | 999 | /* default setup - TODO: look at flags */ |
1000 | if (first_open) { /* First device open */ | 1000 | if (first_open) { /* First device open */ |
1001 | zr36057_restart(zr); | 1001 | zr36057_restart(zr); |
1002 | zoran_open_init_params(zr); | 1002 | zoran_open_init_params(zr); |
1003 | zoran_init_hardware(zr); | 1003 | zoran_init_hardware(zr); |
1004 | 1004 | ||
1005 | btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); | 1005 | btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | /* set file_ops stuff */ | 1008 | /* set file_ops stuff */ |
1009 | file->private_data = fh; | 1009 | file->private_data = fh; |
1010 | fh->zr = zr; | 1010 | fh->zr = zr; |
1011 | zoran_open_init_session(file); | 1011 | zoran_open_init_session(file); |
1012 | unlock_kernel(); | 1012 | unlock_kernel(); |
1013 | 1013 | ||
1014 | return 0; | 1014 | return 0; |
1015 | 1015 | ||
1016 | fail_fh: | 1016 | fail_fh: |
1017 | kfree(fh); | 1017 | kfree(fh); |
1018 | fail_unlock: | 1018 | fail_unlock: |
1019 | unlock_kernel(); | 1019 | unlock_kernel(); |
1020 | 1020 | ||
1021 | dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n", | 1021 | dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n", |
1022 | ZR_DEVNAME(zr), res, zr->user); | 1022 | ZR_DEVNAME(zr), res, zr->user); |
1023 | 1023 | ||
1024 | return res; | 1024 | return res; |
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | static int | 1027 | static int |
1028 | zoran_close(struct file *file) | 1028 | zoran_close(struct file *file) |
1029 | { | 1029 | { |
1030 | struct zoran_fh *fh = file->private_data; | 1030 | struct zoran_fh *fh = file->private_data; |
1031 | struct zoran *zr = fh->zr; | 1031 | struct zoran *zr = fh->zr; |
1032 | 1032 | ||
1033 | dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n", | 1033 | dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n", |
1034 | ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1); | 1034 | ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1); |
1035 | 1035 | ||
1036 | /* kernel locks (fs/device.c), so don't do that ourselves | 1036 | /* kernel locks (fs/device.c), so don't do that ourselves |
1037 | * (prevents deadlocks) */ | 1037 | * (prevents deadlocks) */ |
1038 | /*mutex_lock(&zr->resource_lock);*/ | 1038 | /*mutex_lock(&zr->resource_lock);*/ |
1039 | 1039 | ||
1040 | zoran_close_end_session(file); | 1040 | zoran_close_end_session(file); |
1041 | 1041 | ||
1042 | if (zr->user-- == 1) { /* Last process */ | 1042 | if (zr->user-- == 1) { /* Last process */ |
1043 | /* Clean up JPEG process */ | 1043 | /* Clean up JPEG process */ |
1044 | wake_up_interruptible(&zr->jpg_capq); | 1044 | wake_up_interruptible(&zr->jpg_capq); |
1045 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); | 1045 | zr36057_enable_jpg(zr, BUZ_MODE_IDLE); |
1046 | zr->jpg_buffers.allocated = 0; | 1046 | zr->jpg_buffers.allocated = 0; |
1047 | zr->jpg_buffers.active = ZORAN_FREE; | 1047 | zr->jpg_buffers.active = ZORAN_FREE; |
1048 | 1048 | ||
1049 | /* disable interrupts */ | 1049 | /* disable interrupts */ |
1050 | btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); | 1050 | btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); |
1051 | 1051 | ||
1052 | if (zr36067_debug > 1) | 1052 | if (zr36067_debug > 1) |
1053 | print_interrupts(zr); | 1053 | print_interrupts(zr); |
1054 | 1054 | ||
1055 | /* Overlay off */ | 1055 | /* Overlay off */ |
1056 | zr->v4l_overlay_active = 0; | 1056 | zr->v4l_overlay_active = 0; |
1057 | zr36057_overlay(zr, 0); | 1057 | zr36057_overlay(zr, 0); |
1058 | zr->overlay_mask = NULL; | 1058 | zr->overlay_mask = NULL; |
1059 | 1059 | ||
1060 | /* capture off */ | 1060 | /* capture off */ |
1061 | wake_up_interruptible(&zr->v4l_capq); | 1061 | wake_up_interruptible(&zr->v4l_capq); |
1062 | zr36057_set_memgrab(zr, 0); | 1062 | zr36057_set_memgrab(zr, 0); |
1063 | zr->v4l_buffers.allocated = 0; | 1063 | zr->v4l_buffers.allocated = 0; |
1064 | zr->v4l_buffers.active = ZORAN_FREE; | 1064 | zr->v4l_buffers.active = ZORAN_FREE; |
1065 | zoran_set_pci_master(zr, 0); | 1065 | zoran_set_pci_master(zr, 0); |
1066 | 1066 | ||
1067 | if (!pass_through) { /* Switch to color bar */ | 1067 | if (!pass_through) { /* Switch to color bar */ |
1068 | struct v4l2_routing route = { 2, 0 }; | 1068 | struct v4l2_routing route = { 2, 0 }; |
1069 | 1069 | ||
1070 | decoder_call(zr, video, s_stream, 0); | 1070 | decoder_call(zr, video, s_stream, 0); |
1071 | encoder_call(zr, video, s_routing, &route); | 1071 | encoder_call(zr, video, s_routing, &route); |
1072 | } | 1072 | } |
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | file->private_data = NULL; | 1075 | file->private_data = NULL; |
1076 | kfree(fh->overlay_mask); | 1076 | kfree(fh->overlay_mask); |
1077 | kfree(fh); | 1077 | kfree(fh); |
1078 | 1078 | ||
1079 | dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr)); | 1079 | dprintk(4, KERN_INFO "%s: zoran_close() done\n", ZR_DEVNAME(zr)); |
1080 | 1080 | ||
1081 | return 0; | 1081 | return 0; |
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | 1084 | ||
1085 | static ssize_t | 1085 | static ssize_t |
1086 | zoran_read (struct file *file, | 1086 | zoran_read (struct file *file, |
1087 | char __user *data, | 1087 | char __user *data, |
1088 | size_t count, | 1088 | size_t count, |
1089 | loff_t *ppos) | 1089 | loff_t *ppos) |
1090 | { | 1090 | { |
1091 | /* we simply don't support read() (yet)... */ | 1091 | /* we simply don't support read() (yet)... */ |
1092 | 1092 | ||
1093 | return -EINVAL; | 1093 | return -EINVAL; |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | static ssize_t | 1096 | static ssize_t |
1097 | zoran_write (struct file *file, | 1097 | zoran_write (struct file *file, |
1098 | const char __user *data, | 1098 | const char __user *data, |
1099 | size_t count, | 1099 | size_t count, |
1100 | loff_t *ppos) | 1100 | loff_t *ppos) |
1101 | { | 1101 | { |
1102 | /* ...and the same goes for write() */ | 1102 | /* ...and the same goes for write() */ |
1103 | 1103 | ||
1104 | return -EINVAL; | 1104 | return -EINVAL; |
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | static int | 1107 | static int |
1108 | setup_fbuffer (struct file *file, | 1108 | setup_fbuffer (struct file *file, |
1109 | void *base, | 1109 | void *base, |
1110 | const struct zoran_format *fmt, | 1110 | const struct zoran_format *fmt, |
1111 | int width, | 1111 | int width, |
1112 | int height, | 1112 | int height, |
1113 | int bytesperline) | 1113 | int bytesperline) |
1114 | { | 1114 | { |
1115 | struct zoran_fh *fh = file->private_data; | 1115 | struct zoran_fh *fh = file->private_data; |
1116 | struct zoran *zr = fh->zr; | 1116 | struct zoran *zr = fh->zr; |
1117 | 1117 | ||
1118 | /* (Ronald) v4l/v4l2 guidelines */ | 1118 | /* (Ronald) v4l/v4l2 guidelines */ |
1119 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | 1119 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) |
1120 | return -EPERM; | 1120 | return -EPERM; |
1121 | 1121 | ||
1122 | /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on | 1122 | /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on |
1123 | ALi Magik (that needs very low latency while the card needs a | 1123 | ALi Magik (that needs very low latency while the card needs a |
1124 | higher value always) */ | 1124 | higher value always) */ |
1125 | 1125 | ||
1126 | if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) | 1126 | if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) |
1127 | return -ENXIO; | 1127 | return -ENXIO; |
1128 | 1128 | ||
1129 | /* we need a bytesperline value, even if not given */ | 1129 | /* we need a bytesperline value, even if not given */ |
1130 | if (!bytesperline) | 1130 | if (!bytesperline) |
1131 | bytesperline = width * ((fmt->depth + 7) & ~7) / 8; | 1131 | bytesperline = width * ((fmt->depth + 7) & ~7) / 8; |
1132 | 1132 | ||
1133 | #if 0 | 1133 | #if 0 |
1134 | if (zr->overlay_active) { | 1134 | if (zr->overlay_active) { |
1135 | /* dzjee... stupid users... don't even bother to turn off | 1135 | /* dzjee... stupid users... don't even bother to turn off |
1136 | * overlay before changing the memory location... | 1136 | * overlay before changing the memory location... |
1137 | * normally, we would return errors here. However, one of | 1137 | * normally, we would return errors here. However, one of |
1138 | * the tools that does this is... xawtv! and since xawtv | 1138 | * the tools that does this is... xawtv! and since xawtv |
1139 | * is used by +/- 99% of the users, we'd rather be user- | 1139 | * is used by +/- 99% of the users, we'd rather be user- |
1140 | * friendly and silently do as if nothing went wrong */ | 1140 | * friendly and silently do as if nothing went wrong */ |
1141 | dprintk(3, | 1141 | dprintk(3, |
1142 | KERN_ERR | 1142 | KERN_ERR |
1143 | "%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n", | 1143 | "%s: setup_fbuffer() - forced overlay turnoff because framebuffer changed\n", |
1144 | ZR_DEVNAME(zr)); | 1144 | ZR_DEVNAME(zr)); |
1145 | zr36057_overlay(zr, 0); | 1145 | zr36057_overlay(zr, 0); |
1146 | } | 1146 | } |
1147 | #endif | 1147 | #endif |
1148 | 1148 | ||
1149 | if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) { | 1149 | if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) { |
1150 | dprintk(1, | 1150 | dprintk(1, |
1151 | KERN_ERR | 1151 | KERN_ERR |
1152 | "%s: setup_fbuffer() - no valid overlay format given\n", | 1152 | "%s: setup_fbuffer() - no valid overlay format given\n", |
1153 | ZR_DEVNAME(zr)); | 1153 | ZR_DEVNAME(zr)); |
1154 | return -EINVAL; | 1154 | return -EINVAL; |
1155 | } | 1155 | } |
1156 | if (height <= 0 || width <= 0 || bytesperline <= 0) { | 1156 | if (height <= 0 || width <= 0 || bytesperline <= 0) { |
1157 | dprintk(1, | 1157 | dprintk(1, |
1158 | KERN_ERR | 1158 | KERN_ERR |
1159 | "%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n", | 1159 | "%s: setup_fbuffer() - invalid height/width/bpl value (%d|%d|%d)\n", |
1160 | ZR_DEVNAME(zr), width, height, bytesperline); | 1160 | ZR_DEVNAME(zr), width, height, bytesperline); |
1161 | return -EINVAL; | 1161 | return -EINVAL; |
1162 | } | 1162 | } |
1163 | if (bytesperline & 3) { | 1163 | if (bytesperline & 3) { |
1164 | dprintk(1, | 1164 | dprintk(1, |
1165 | KERN_ERR | 1165 | KERN_ERR |
1166 | "%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n", | 1166 | "%s: setup_fbuffer() - bytesperline (%d) must be 4-byte aligned\n", |
1167 | ZR_DEVNAME(zr), bytesperline); | 1167 | ZR_DEVNAME(zr), bytesperline); |
1168 | return -EINVAL; | 1168 | return -EINVAL; |
1169 | } | 1169 | } |
1170 | 1170 | ||
1171 | zr->vbuf_base = (void *) ((unsigned long) base & ~3); | 1171 | zr->vbuf_base = (void *) ((unsigned long) base & ~3); |
1172 | zr->vbuf_height = height; | 1172 | zr->vbuf_height = height; |
1173 | zr->vbuf_width = width; | 1173 | zr->vbuf_width = width; |
1174 | zr->vbuf_depth = fmt->depth; | 1174 | zr->vbuf_depth = fmt->depth; |
1175 | zr->overlay_settings.format = fmt; | 1175 | zr->overlay_settings.format = fmt; |
1176 | zr->vbuf_bytesperline = bytesperline; | 1176 | zr->vbuf_bytesperline = bytesperline; |
1177 | 1177 | ||
1178 | /* The user should set new window parameters */ | 1178 | /* The user should set new window parameters */ |
1179 | zr->overlay_settings.is_set = 0; | 1179 | zr->overlay_settings.is_set = 0; |
1180 | 1180 | ||
1181 | return 0; | 1181 | return 0; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | 1184 | ||
1185 | static int | 1185 | static int |
1186 | setup_window (struct file *file, | 1186 | setup_window (struct file *file, |
1187 | int x, | 1187 | int x, |
1188 | int y, | 1188 | int y, |
1189 | int width, | 1189 | int width, |
1190 | int height, | 1190 | int height, |
1191 | struct v4l2_clip __user *clips, | 1191 | struct v4l2_clip __user *clips, |
1192 | int clipcount, | 1192 | int clipcount, |
1193 | void __user *bitmap) | 1193 | void __user *bitmap) |
1194 | { | 1194 | { |
1195 | struct zoran_fh *fh = file->private_data; | 1195 | struct zoran_fh *fh = file->private_data; |
1196 | struct zoran *zr = fh->zr; | 1196 | struct zoran *zr = fh->zr; |
1197 | struct v4l2_clip *vcp = NULL; | 1197 | struct v4l2_clip *vcp = NULL; |
1198 | int on, end; | 1198 | int on, end; |
1199 | 1199 | ||
1200 | 1200 | ||
1201 | if (!zr->vbuf_base) { | 1201 | if (!zr->vbuf_base) { |
1202 | dprintk(1, | 1202 | dprintk(1, |
1203 | KERN_ERR | 1203 | KERN_ERR |
1204 | "%s: setup_window() - frame buffer has to be set first\n", | 1204 | "%s: setup_window() - frame buffer has to be set first\n", |
1205 | ZR_DEVNAME(zr)); | 1205 | ZR_DEVNAME(zr)); |
1206 | return -EINVAL; | 1206 | return -EINVAL; |
1207 | } | 1207 | } |
1208 | 1208 | ||
1209 | if (!fh->overlay_settings.format) { | 1209 | if (!fh->overlay_settings.format) { |
1210 | dprintk(1, | 1210 | dprintk(1, |
1211 | KERN_ERR | 1211 | KERN_ERR |
1212 | "%s: setup_window() - no overlay format set\n", | 1212 | "%s: setup_window() - no overlay format set\n", |
1213 | ZR_DEVNAME(zr)); | 1213 | ZR_DEVNAME(zr)); |
1214 | return -EINVAL; | 1214 | return -EINVAL; |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | /* | 1217 | /* |
1218 | * The video front end needs 4-byte alinged line sizes, we correct that | 1218 | * The video front end needs 4-byte alinged line sizes, we correct that |
1219 | * silently here if necessary | 1219 | * silently here if necessary |
1220 | */ | 1220 | */ |
1221 | if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) { | 1221 | if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) { |
1222 | end = (x + width) & ~1; /* round down */ | 1222 | end = (x + width) & ~1; /* round down */ |
1223 | x = (x + 1) & ~1; /* round up */ | 1223 | x = (x + 1) & ~1; /* round up */ |
1224 | width = end - x; | 1224 | width = end - x; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | if (zr->vbuf_depth == 24) { | 1227 | if (zr->vbuf_depth == 24) { |
1228 | end = (x + width) & ~3; /* round down */ | 1228 | end = (x + width) & ~3; /* round down */ |
1229 | x = (x + 3) & ~3; /* round up */ | 1229 | x = (x + 3) & ~3; /* round up */ |
1230 | width = end - x; | 1230 | width = end - x; |
1231 | } | 1231 | } |
1232 | 1232 | ||
1233 | if (width > BUZ_MAX_WIDTH) | 1233 | if (width > BUZ_MAX_WIDTH) |
1234 | width = BUZ_MAX_WIDTH; | 1234 | width = BUZ_MAX_WIDTH; |
1235 | if (height > BUZ_MAX_HEIGHT) | 1235 | if (height > BUZ_MAX_HEIGHT) |
1236 | height = BUZ_MAX_HEIGHT; | 1236 | height = BUZ_MAX_HEIGHT; |
1237 | 1237 | ||
1238 | /* Check for vaild parameters */ | 1238 | /* Check for vaild parameters */ |
1239 | if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT || | 1239 | if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT || |
1240 | width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) { | 1240 | width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) { |
1241 | dprintk(1, | 1241 | dprintk(1, |
1242 | KERN_ERR | 1242 | KERN_ERR |
1243 | "%s: setup_window() - width = %d or height = %d invalid\n", | 1243 | "%s: setup_window() - width = %d or height = %d invalid\n", |
1244 | ZR_DEVNAME(zr), width, height); | 1244 | ZR_DEVNAME(zr), width, height); |
1245 | return -EINVAL; | 1245 | return -EINVAL; |
1246 | } | 1246 | } |
1247 | 1247 | ||
1248 | fh->overlay_settings.x = x; | 1248 | fh->overlay_settings.x = x; |
1249 | fh->overlay_settings.y = y; | 1249 | fh->overlay_settings.y = y; |
1250 | fh->overlay_settings.width = width; | 1250 | fh->overlay_settings.width = width; |
1251 | fh->overlay_settings.height = height; | 1251 | fh->overlay_settings.height = height; |
1252 | fh->overlay_settings.clipcount = clipcount; | 1252 | fh->overlay_settings.clipcount = clipcount; |
1253 | 1253 | ||
1254 | /* | 1254 | /* |
1255 | * If an overlay is running, we have to switch it off | 1255 | * If an overlay is running, we have to switch it off |
1256 | * and switch it on again in order to get the new settings in effect. | 1256 | * and switch it on again in order to get the new settings in effect. |
1257 | * | 1257 | * |
1258 | * We also want to avoid that the overlay mask is written | 1258 | * We also want to avoid that the overlay mask is written |
1259 | * when an overlay is running. | 1259 | * when an overlay is running. |
1260 | */ | 1260 | */ |
1261 | 1261 | ||
1262 | on = zr->v4l_overlay_active && !zr->v4l_memgrab_active && | 1262 | on = zr->v4l_overlay_active && !zr->v4l_memgrab_active && |
1263 | zr->overlay_active != ZORAN_FREE && | 1263 | zr->overlay_active != ZORAN_FREE && |
1264 | fh->overlay_active != ZORAN_FREE; | 1264 | fh->overlay_active != ZORAN_FREE; |
1265 | if (on) | 1265 | if (on) |
1266 | zr36057_overlay(zr, 0); | 1266 | zr36057_overlay(zr, 0); |
1267 | 1267 | ||
1268 | /* | 1268 | /* |
1269 | * Write the overlay mask if clips are wanted. | 1269 | * Write the overlay mask if clips are wanted. |
1270 | * We prefer a bitmap. | 1270 | * We prefer a bitmap. |
1271 | */ | 1271 | */ |
1272 | if (bitmap) { | 1272 | if (bitmap) { |
1273 | /* fake value - it just means we want clips */ | 1273 | /* fake value - it just means we want clips */ |
1274 | fh->overlay_settings.clipcount = 1; | 1274 | fh->overlay_settings.clipcount = 1; |
1275 | 1275 | ||
1276 | if (copy_from_user(fh->overlay_mask, bitmap, | 1276 | if (copy_from_user(fh->overlay_mask, bitmap, |
1277 | (width * height + 7) / 8)) { | 1277 | (width * height + 7) / 8)) { |
1278 | return -EFAULT; | 1278 | return -EFAULT; |
1279 | } | 1279 | } |
1280 | } else if (clipcount > 0) { | 1280 | } else if (clipcount > 0) { |
1281 | /* write our own bitmap from the clips */ | 1281 | /* write our own bitmap from the clips */ |
1282 | vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4)); | 1282 | vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4)); |
1283 | if (vcp == NULL) { | 1283 | if (vcp == NULL) { |
1284 | dprintk(1, | 1284 | dprintk(1, |
1285 | KERN_ERR | 1285 | KERN_ERR |
1286 | "%s: setup_window() - Alloc of clip mask failed\n", | 1286 | "%s: setup_window() - Alloc of clip mask failed\n", |
1287 | ZR_DEVNAME(zr)); | 1287 | ZR_DEVNAME(zr)); |
1288 | return -ENOMEM; | 1288 | return -ENOMEM; |
1289 | } | 1289 | } |
1290 | if (copy_from_user | 1290 | if (copy_from_user |
1291 | (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) { | 1291 | (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) { |
1292 | vfree(vcp); | 1292 | vfree(vcp); |
1293 | return -EFAULT; | 1293 | return -EFAULT; |
1294 | } | 1294 | } |
1295 | write_overlay_mask(file, vcp, clipcount); | 1295 | write_overlay_mask(file, vcp, clipcount); |
1296 | vfree(vcp); | 1296 | vfree(vcp); |
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | fh->overlay_settings.is_set = 1; | 1299 | fh->overlay_settings.is_set = 1; |
1300 | if (fh->overlay_active != ZORAN_FREE && | 1300 | if (fh->overlay_active != ZORAN_FREE && |
1301 | zr->overlay_active != ZORAN_FREE) | 1301 | zr->overlay_active != ZORAN_FREE) |
1302 | zr->overlay_settings = fh->overlay_settings; | 1302 | zr->overlay_settings = fh->overlay_settings; |
1303 | 1303 | ||
1304 | if (on) | 1304 | if (on) |
1305 | zr36057_overlay(zr, 1); | 1305 | zr36057_overlay(zr, 1); |
1306 | 1306 | ||
1307 | /* Make sure the changes come into effect */ | 1307 | /* Make sure the changes come into effect */ |
1308 | return wait_grab_pending(zr); | 1308 | return wait_grab_pending(zr); |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | static int | 1311 | static int |
1312 | setup_overlay (struct file *file, | 1312 | setup_overlay (struct file *file, |
1313 | int on) | 1313 | int on) |
1314 | { | 1314 | { |
1315 | struct zoran_fh *fh = file->private_data; | 1315 | struct zoran_fh *fh = file->private_data; |
1316 | struct zoran *zr = fh->zr; | 1316 | struct zoran *zr = fh->zr; |
1317 | 1317 | ||
1318 | /* If there is nothing to do, return immediatly */ | 1318 | /* If there is nothing to do, return immediatly */ |
1319 | if ((on && fh->overlay_active != ZORAN_FREE) || | 1319 | if ((on && fh->overlay_active != ZORAN_FREE) || |
1320 | (!on && fh->overlay_active == ZORAN_FREE)) | 1320 | (!on && fh->overlay_active == ZORAN_FREE)) |
1321 | return 0; | 1321 | return 0; |
1322 | 1322 | ||
1323 | /* check whether we're touching someone else's overlay */ | 1323 | /* check whether we're touching someone else's overlay */ |
1324 | if (on && zr->overlay_active != ZORAN_FREE && | 1324 | if (on && zr->overlay_active != ZORAN_FREE && |
1325 | fh->overlay_active == ZORAN_FREE) { | 1325 | fh->overlay_active == ZORAN_FREE) { |
1326 | dprintk(1, | 1326 | dprintk(1, |
1327 | KERN_ERR | 1327 | KERN_ERR |
1328 | "%s: setup_overlay() - overlay is already active for another session\n", | 1328 | "%s: setup_overlay() - overlay is already active for another session\n", |
1329 | ZR_DEVNAME(zr)); | 1329 | ZR_DEVNAME(zr)); |
1330 | return -EBUSY; | 1330 | return -EBUSY; |
1331 | } | 1331 | } |
1332 | if (!on && zr->overlay_active != ZORAN_FREE && | 1332 | if (!on && zr->overlay_active != ZORAN_FREE && |
1333 | fh->overlay_active == ZORAN_FREE) { | 1333 | fh->overlay_active == ZORAN_FREE) { |
1334 | dprintk(1, | 1334 | dprintk(1, |
1335 | KERN_ERR | 1335 | KERN_ERR |
1336 | "%s: setup_overlay() - you cannot cancel someone else's session\n", | 1336 | "%s: setup_overlay() - you cannot cancel someone else's session\n", |
1337 | ZR_DEVNAME(zr)); | 1337 | ZR_DEVNAME(zr)); |
1338 | return -EPERM; | 1338 | return -EPERM; |
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | if (on == 0) { | 1341 | if (on == 0) { |
1342 | zr->overlay_active = fh->overlay_active = ZORAN_FREE; | 1342 | zr->overlay_active = fh->overlay_active = ZORAN_FREE; |
1343 | zr->v4l_overlay_active = 0; | 1343 | zr->v4l_overlay_active = 0; |
1344 | /* When a grab is running, the video simply | 1344 | /* When a grab is running, the video simply |
1345 | * won't be switched on any more */ | 1345 | * won't be switched on any more */ |
1346 | if (!zr->v4l_memgrab_active) | 1346 | if (!zr->v4l_memgrab_active) |
1347 | zr36057_overlay(zr, 0); | 1347 | zr36057_overlay(zr, 0); |
1348 | zr->overlay_mask = NULL; | 1348 | zr->overlay_mask = NULL; |
1349 | } else { | 1349 | } else { |
1350 | if (!zr->vbuf_base || !fh->overlay_settings.is_set) { | 1350 | if (!zr->vbuf_base || !fh->overlay_settings.is_set) { |
1351 | dprintk(1, | 1351 | dprintk(1, |
1352 | KERN_ERR | 1352 | KERN_ERR |
1353 | "%s: setup_overlay() - buffer or window not set\n", | 1353 | "%s: setup_overlay() - buffer or window not set\n", |
1354 | ZR_DEVNAME(zr)); | 1354 | ZR_DEVNAME(zr)); |
1355 | return -EINVAL; | 1355 | return -EINVAL; |
1356 | } | 1356 | } |
1357 | if (!fh->overlay_settings.format) { | 1357 | if (!fh->overlay_settings.format) { |
1358 | dprintk(1, | 1358 | dprintk(1, |
1359 | KERN_ERR | 1359 | KERN_ERR |
1360 | "%s: setup_overlay() - no overlay format set\n", | 1360 | "%s: setup_overlay() - no overlay format set\n", |
1361 | ZR_DEVNAME(zr)); | 1361 | ZR_DEVNAME(zr)); |
1362 | return -EINVAL; | 1362 | return -EINVAL; |
1363 | } | 1363 | } |
1364 | zr->overlay_active = fh->overlay_active = ZORAN_LOCKED; | 1364 | zr->overlay_active = fh->overlay_active = ZORAN_LOCKED; |
1365 | zr->v4l_overlay_active = 1; | 1365 | zr->v4l_overlay_active = 1; |
1366 | zr->overlay_mask = fh->overlay_mask; | 1366 | zr->overlay_mask = fh->overlay_mask; |
1367 | zr->overlay_settings = fh->overlay_settings; | 1367 | zr->overlay_settings = fh->overlay_settings; |
1368 | if (!zr->v4l_memgrab_active) | 1368 | if (!zr->v4l_memgrab_active) |
1369 | zr36057_overlay(zr, 1); | 1369 | zr36057_overlay(zr, 1); |
1370 | /* When a grab is running, the video will be | 1370 | /* When a grab is running, the video will be |
1371 | * switched on when grab is finished */ | 1371 | * switched on when grab is finished */ |
1372 | } | 1372 | } |
1373 | 1373 | ||
1374 | /* Make sure the changes come into effect */ | 1374 | /* Make sure the changes come into effect */ |
1375 | return wait_grab_pending(zr); | 1375 | return wait_grab_pending(zr); |
1376 | } | 1376 | } |
1377 | 1377 | ||
1378 | /* get the status of a buffer in the clients buffer queue */ | 1378 | /* get the status of a buffer in the clients buffer queue */ |
1379 | static int | 1379 | static int |
1380 | zoran_v4l2_buffer_status (struct zoran_fh *fh, | 1380 | zoran_v4l2_buffer_status (struct zoran_fh *fh, |
1381 | struct v4l2_buffer *buf, | 1381 | struct v4l2_buffer *buf, |
1382 | int num) | 1382 | int num) |
1383 | { | 1383 | { |
1384 | struct zoran *zr = fh->zr; | 1384 | struct zoran *zr = fh->zr; |
1385 | 1385 | ||
1386 | buf->flags = V4L2_BUF_FLAG_MAPPED; | 1386 | buf->flags = V4L2_BUF_FLAG_MAPPED; |
1387 | 1387 | ||
1388 | switch (fh->map_mode) { | 1388 | switch (fh->map_mode) { |
1389 | case ZORAN_MAP_MODE_RAW: | 1389 | case ZORAN_MAP_MODE_RAW: |
1390 | 1390 | ||
1391 | /* check range */ | 1391 | /* check range */ |
1392 | if (num < 0 || num >= fh->v4l_buffers.num_buffers || | 1392 | if (num < 0 || num >= fh->v4l_buffers.num_buffers || |
1393 | !fh->v4l_buffers.allocated) { | 1393 | !fh->v4l_buffers.allocated) { |
1394 | dprintk(1, | 1394 | dprintk(1, |
1395 | KERN_ERR | 1395 | KERN_ERR |
1396 | "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n", | 1396 | "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n", |
1397 | ZR_DEVNAME(zr)); | 1397 | ZR_DEVNAME(zr)); |
1398 | return -EINVAL; | 1398 | return -EINVAL; |
1399 | } | 1399 | } |
1400 | 1400 | ||
1401 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1401 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1402 | buf->length = fh->v4l_buffers.buffer_size; | 1402 | buf->length = fh->v4l_buffers.buffer_size; |
1403 | 1403 | ||
1404 | /* get buffer */ | 1404 | /* get buffer */ |
1405 | buf->bytesused = fh->v4l_buffers.buffer[num].bs.length; | 1405 | buf->bytesused = fh->v4l_buffers.buffer[num].bs.length; |
1406 | if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE || | 1406 | if (fh->v4l_buffers.buffer[num].state == BUZ_STATE_DONE || |
1407 | fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) { | 1407 | fh->v4l_buffers.buffer[num].state == BUZ_STATE_USER) { |
1408 | buf->sequence = fh->v4l_buffers.buffer[num].bs.seq; | 1408 | buf->sequence = fh->v4l_buffers.buffer[num].bs.seq; |
1409 | buf->flags |= V4L2_BUF_FLAG_DONE; | 1409 | buf->flags |= V4L2_BUF_FLAG_DONE; |
1410 | buf->timestamp = | 1410 | buf->timestamp = |
1411 | fh->v4l_buffers.buffer[num].bs.timestamp; | 1411 | fh->v4l_buffers.buffer[num].bs.timestamp; |
1412 | } else { | 1412 | } else { |
1413 | buf->flags |= V4L2_BUF_FLAG_QUEUED; | 1413 | buf->flags |= V4L2_BUF_FLAG_QUEUED; |
1414 | } | 1414 | } |
1415 | 1415 | ||
1416 | if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2) | 1416 | if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2) |
1417 | buf->field = V4L2_FIELD_TOP; | 1417 | buf->field = V4L2_FIELD_TOP; |
1418 | else | 1418 | else |
1419 | buf->field = V4L2_FIELD_INTERLACED; | 1419 | buf->field = V4L2_FIELD_INTERLACED; |
1420 | 1420 | ||
1421 | break; | 1421 | break; |
1422 | 1422 | ||
1423 | case ZORAN_MAP_MODE_JPG_REC: | 1423 | case ZORAN_MAP_MODE_JPG_REC: |
1424 | case ZORAN_MAP_MODE_JPG_PLAY: | 1424 | case ZORAN_MAP_MODE_JPG_PLAY: |
1425 | 1425 | ||
1426 | /* check range */ | 1426 | /* check range */ |
1427 | if (num < 0 || num >= fh->jpg_buffers.num_buffers || | 1427 | if (num < 0 || num >= fh->jpg_buffers.num_buffers || |
1428 | !fh->jpg_buffers.allocated) { | 1428 | !fh->jpg_buffers.allocated) { |
1429 | dprintk(1, | 1429 | dprintk(1, |
1430 | KERN_ERR | 1430 | KERN_ERR |
1431 | "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n", | 1431 | "%s: v4l2_buffer_status() - wrong number or buffers not allocated\n", |
1432 | ZR_DEVNAME(zr)); | 1432 | ZR_DEVNAME(zr)); |
1433 | return -EINVAL; | 1433 | return -EINVAL; |
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? | 1436 | buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? |
1437 | V4L2_BUF_TYPE_VIDEO_CAPTURE : | 1437 | V4L2_BUF_TYPE_VIDEO_CAPTURE : |
1438 | V4L2_BUF_TYPE_VIDEO_OUTPUT; | 1438 | V4L2_BUF_TYPE_VIDEO_OUTPUT; |
1439 | buf->length = fh->jpg_buffers.buffer_size; | 1439 | buf->length = fh->jpg_buffers.buffer_size; |
1440 | 1440 | ||
1441 | /* these variables are only written after frame has been captured */ | 1441 | /* these variables are only written after frame has been captured */ |
1442 | if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE || | 1442 | if (fh->jpg_buffers.buffer[num].state == BUZ_STATE_DONE || |
1443 | fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) { | 1443 | fh->jpg_buffers.buffer[num].state == BUZ_STATE_USER) { |
1444 | buf->sequence = fh->jpg_buffers.buffer[num].bs.seq; | 1444 | buf->sequence = fh->jpg_buffers.buffer[num].bs.seq; |
1445 | buf->timestamp = | 1445 | buf->timestamp = |
1446 | fh->jpg_buffers.buffer[num].bs.timestamp; | 1446 | fh->jpg_buffers.buffer[num].bs.timestamp; |
1447 | buf->bytesused = | 1447 | buf->bytesused = |
1448 | fh->jpg_buffers.buffer[num].bs.length; | 1448 | fh->jpg_buffers.buffer[num].bs.length; |
1449 | buf->flags |= V4L2_BUF_FLAG_DONE; | 1449 | buf->flags |= V4L2_BUF_FLAG_DONE; |
1450 | } else { | 1450 | } else { |
1451 | buf->flags |= V4L2_BUF_FLAG_QUEUED; | 1451 | buf->flags |= V4L2_BUF_FLAG_QUEUED; |
1452 | } | 1452 | } |
1453 | 1453 | ||
1454 | /* which fields are these? */ | 1454 | /* which fields are these? */ |
1455 | if (fh->jpg_settings.TmpDcm != 1) | 1455 | if (fh->jpg_settings.TmpDcm != 1) |
1456 | buf->field = | 1456 | buf->field = |
1457 | fh->jpg_settings. | 1457 | fh->jpg_settings. |
1458 | odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; | 1458 | odd_even ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; |
1459 | else | 1459 | else |
1460 | buf->field = | 1460 | buf->field = |
1461 | fh->jpg_settings. | 1461 | fh->jpg_settings. |
1462 | odd_even ? V4L2_FIELD_SEQ_TB : | 1462 | odd_even ? V4L2_FIELD_SEQ_TB : |
1463 | V4L2_FIELD_SEQ_BT; | 1463 | V4L2_FIELD_SEQ_BT; |
1464 | 1464 | ||
1465 | break; | 1465 | break; |
1466 | 1466 | ||
1467 | default: | 1467 | default: |
1468 | 1468 | ||
1469 | dprintk(5, | 1469 | dprintk(5, |
1470 | KERN_ERR | 1470 | KERN_ERR |
1471 | "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n", | 1471 | "%s: v4l2_buffer_status() - invalid buffer type|map_mode (%d|%d)\n", |
1472 | ZR_DEVNAME(zr), buf->type, fh->map_mode); | 1472 | ZR_DEVNAME(zr), buf->type, fh->map_mode); |
1473 | return -EINVAL; | 1473 | return -EINVAL; |
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | buf->memory = V4L2_MEMORY_MMAP; | 1476 | buf->memory = V4L2_MEMORY_MMAP; |
1477 | buf->index = num; | 1477 | buf->index = num; |
1478 | buf->m.offset = buf->length * num; | 1478 | buf->m.offset = buf->length * num; |
1479 | 1479 | ||
1480 | return 0; | 1480 | return 0; |
1481 | } | 1481 | } |
1482 | 1482 | ||
1483 | static int | 1483 | static int |
1484 | zoran_set_norm (struct zoran *zr, | 1484 | zoran_set_norm (struct zoran *zr, |
1485 | v4l2_std_id norm) | 1485 | v4l2_std_id norm) |
1486 | { | 1486 | { |
1487 | int on; | 1487 | int on; |
1488 | 1488 | ||
1489 | if (zr->v4l_buffers.active != ZORAN_FREE || | 1489 | if (zr->v4l_buffers.active != ZORAN_FREE || |
1490 | zr->jpg_buffers.active != ZORAN_FREE) { | 1490 | zr->jpg_buffers.active != ZORAN_FREE) { |
1491 | dprintk(1, | 1491 | dprintk(1, |
1492 | KERN_WARNING | 1492 | KERN_WARNING |
1493 | "%s: set_norm() called while in playback/capture mode\n", | 1493 | "%s: set_norm() called while in playback/capture mode\n", |
1494 | ZR_DEVNAME(zr)); | 1494 | ZR_DEVNAME(zr)); |
1495 | return -EBUSY; | 1495 | return -EBUSY; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | if (lock_norm && norm != zr->norm) { | 1498 | if (lock_norm && norm != zr->norm) { |
1499 | if (lock_norm > 1) { | 1499 | if (lock_norm > 1) { |
1500 | dprintk(1, | 1500 | dprintk(1, |
1501 | KERN_WARNING | 1501 | KERN_WARNING |
1502 | "%s: set_norm() - TV standard is locked, can not switch norm\n", | 1502 | "%s: set_norm() - TV standard is locked, can not switch norm\n", |
1503 | ZR_DEVNAME(zr)); | 1503 | ZR_DEVNAME(zr)); |
1504 | return -EPERM; | 1504 | return -EPERM; |
1505 | } else { | 1505 | } else { |
1506 | dprintk(1, | 1506 | dprintk(1, |
1507 | KERN_WARNING | 1507 | KERN_WARNING |
1508 | "%s: set_norm() - TV standard is locked, norm was not changed\n", | 1508 | "%s: set_norm() - TV standard is locked, norm was not changed\n", |
1509 | ZR_DEVNAME(zr)); | 1509 | ZR_DEVNAME(zr)); |
1510 | norm = zr->norm; | 1510 | norm = zr->norm; |
1511 | } | 1511 | } |
1512 | } | 1512 | } |
1513 | 1513 | ||
1514 | if (!(norm & zr->card.norms)) { | 1514 | if (!(norm & zr->card.norms)) { |
1515 | dprintk(1, | 1515 | dprintk(1, |
1516 | KERN_ERR "%s: set_norm() - unsupported norm %llx\n", | 1516 | KERN_ERR "%s: set_norm() - unsupported norm %llx\n", |
1517 | ZR_DEVNAME(zr), norm); | 1517 | ZR_DEVNAME(zr), norm); |
1518 | return -EINVAL; | 1518 | return -EINVAL; |
1519 | } | 1519 | } |
1520 | 1520 | ||
1521 | if (norm == V4L2_STD_ALL) { | 1521 | if (norm == V4L2_STD_ALL) { |
1522 | int status = 0; | 1522 | int status = 0; |
1523 | v4l2_std_id std = 0; | 1523 | v4l2_std_id std = 0; |
1524 | 1524 | ||
1525 | decoder_call(zr, video, querystd, &std); | 1525 | decoder_call(zr, video, querystd, &std); |
1526 | decoder_s_std(zr, std); | 1526 | decoder_s_std(zr, std); |
1527 | 1527 | ||
1528 | /* let changes come into effect */ | 1528 | /* let changes come into effect */ |
1529 | ssleep(2); | 1529 | ssleep(2); |
1530 | 1530 | ||
1531 | decoder_call(zr, video, g_input_status, &status); | 1531 | decoder_call(zr, video, g_input_status, &status); |
1532 | if (status & V4L2_IN_ST_NO_SIGNAL) { | 1532 | if (status & V4L2_IN_ST_NO_SIGNAL) { |
1533 | dprintk(1, | 1533 | dprintk(1, |
1534 | KERN_ERR | 1534 | KERN_ERR |
1535 | "%s: set_norm() - no norm detected\n", | 1535 | "%s: set_norm() - no norm detected\n", |
1536 | ZR_DEVNAME(zr)); | 1536 | ZR_DEVNAME(zr)); |
1537 | /* reset norm */ | 1537 | /* reset norm */ |
1538 | decoder_s_std(zr, zr->norm); | 1538 | decoder_s_std(zr, zr->norm); |
1539 | return -EIO; | 1539 | return -EIO; |
1540 | } | 1540 | } |
1541 | 1541 | ||
1542 | norm = std; | 1542 | norm = std; |
1543 | } | 1543 | } |
1544 | if (norm & V4L2_STD_SECAM) | 1544 | if (norm & V4L2_STD_SECAM) |
1545 | zr->timing = zr->card.tvn[2]; | 1545 | zr->timing = zr->card.tvn[2]; |
1546 | else if (norm & V4L2_STD_NTSC) | 1546 | else if (norm & V4L2_STD_NTSC) |
1547 | zr->timing = zr->card.tvn[1]; | 1547 | zr->timing = zr->card.tvn[1]; |
1548 | else | 1548 | else |
1549 | zr->timing = zr->card.tvn[0]; | 1549 | zr->timing = zr->card.tvn[0]; |
1550 | 1550 | ||
1551 | /* We switch overlay off and on since a change in the | 1551 | /* We switch overlay off and on since a change in the |
1552 | * norm needs different VFE settings */ | 1552 | * norm needs different VFE settings */ |
1553 | on = zr->overlay_active && !zr->v4l_memgrab_active; | 1553 | on = zr->overlay_active && !zr->v4l_memgrab_active; |
1554 | if (on) | 1554 | if (on) |
1555 | zr36057_overlay(zr, 0); | 1555 | zr36057_overlay(zr, 0); |
1556 | 1556 | ||
1557 | decoder_s_std(zr, norm); | 1557 | decoder_s_std(zr, norm); |
1558 | encoder_call(zr, video, s_std_output, norm); | 1558 | encoder_call(zr, video, s_std_output, norm); |
1559 | 1559 | ||
1560 | if (on) | 1560 | if (on) |
1561 | zr36057_overlay(zr, 1); | 1561 | zr36057_overlay(zr, 1); |
1562 | 1562 | ||
1563 | /* Make sure the changes come into effect */ | 1563 | /* Make sure the changes come into effect */ |
1564 | zr->norm = norm; | 1564 | zr->norm = norm; |
1565 | 1565 | ||
1566 | return 0; | 1566 | return 0; |
1567 | } | 1567 | } |
1568 | 1568 | ||
1569 | static int | 1569 | static int |
1570 | zoran_set_input (struct zoran *zr, | 1570 | zoran_set_input (struct zoran *zr, |
1571 | int input) | 1571 | int input) |
1572 | { | 1572 | { |
1573 | struct v4l2_routing route = { 0, 0 }; | 1573 | struct v4l2_routing route = { 0, 0 }; |
1574 | 1574 | ||
1575 | if (input == zr->input) { | 1575 | if (input == zr->input) { |
1576 | return 0; | 1576 | return 0; |
1577 | } | 1577 | } |
1578 | 1578 | ||
1579 | if (zr->v4l_buffers.active != ZORAN_FREE || | 1579 | if (zr->v4l_buffers.active != ZORAN_FREE || |
1580 | zr->jpg_buffers.active != ZORAN_FREE) { | 1580 | zr->jpg_buffers.active != ZORAN_FREE) { |
1581 | dprintk(1, | 1581 | dprintk(1, |
1582 | KERN_WARNING | 1582 | KERN_WARNING |
1583 | "%s: set_input() called while in playback/capture mode\n", | 1583 | "%s: set_input() called while in playback/capture mode\n", |
1584 | ZR_DEVNAME(zr)); | 1584 | ZR_DEVNAME(zr)); |
1585 | return -EBUSY; | 1585 | return -EBUSY; |
1586 | } | 1586 | } |
1587 | 1587 | ||
1588 | if (input < 0 || input >= zr->card.inputs) { | 1588 | if (input < 0 || input >= zr->card.inputs) { |
1589 | dprintk(1, | 1589 | dprintk(1, |
1590 | KERN_ERR | 1590 | KERN_ERR |
1591 | "%s: set_input() - unnsupported input %d\n", | 1591 | "%s: set_input() - unnsupported input %d\n", |
1592 | ZR_DEVNAME(zr), input); | 1592 | ZR_DEVNAME(zr), input); |
1593 | return -EINVAL; | 1593 | return -EINVAL; |
1594 | } | 1594 | } |
1595 | 1595 | ||
1596 | route.input = zr->card.input[input].muxsel; | 1596 | route.input = zr->card.input[input].muxsel; |
1597 | zr->input = input; | 1597 | zr->input = input; |
1598 | 1598 | ||
1599 | decoder_s_routing(zr, &route); | 1599 | decoder_s_routing(zr, &route); |
1600 | 1600 | ||
1601 | return 0; | 1601 | return 0; |
1602 | } | 1602 | } |
1603 | 1603 | ||
1604 | /* | 1604 | /* |
1605 | * ioctl routine | 1605 | * ioctl routine |
1606 | */ | 1606 | */ |
1607 | 1607 | ||
1608 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1608 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1609 | static long zoran_default(struct file *file, void *__fh, int cmd, void *arg) | 1609 | static long zoran_default(struct file *file, void *__fh, int cmd, void *arg) |
1610 | { | 1610 | { |
1611 | struct zoran_fh *fh = __fh; | 1611 | struct zoran_fh *fh = __fh; |
1612 | struct zoran *zr = fh->zr; | 1612 | struct zoran *zr = fh->zr; |
1613 | struct zoran_jpg_settings settings; | 1613 | struct zoran_jpg_settings settings; |
1614 | 1614 | ||
1615 | switch (cmd) { | 1615 | switch (cmd) { |
1616 | case BUZIOC_G_PARAMS: | 1616 | case BUZIOC_G_PARAMS: |
1617 | { | 1617 | { |
1618 | struct zoran_params *bparams = arg; | 1618 | struct zoran_params *bparams = arg; |
1619 | 1619 | ||
1620 | dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr)); | 1620 | dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr)); |
1621 | 1621 | ||
1622 | memset(bparams, 0, sizeof(struct zoran_params)); | 1622 | memset(bparams, 0, sizeof(struct zoran_params)); |
1623 | bparams->major_version = MAJOR_VERSION; | 1623 | bparams->major_version = MAJOR_VERSION; |
1624 | bparams->minor_version = MINOR_VERSION; | 1624 | bparams->minor_version = MINOR_VERSION; |
1625 | 1625 | ||
1626 | mutex_lock(&zr->resource_lock); | 1626 | mutex_lock(&zr->resource_lock); |
1627 | 1627 | ||
1628 | if (zr->norm & V4L2_STD_NTSC) | 1628 | if (zr->norm & V4L2_STD_NTSC) |
1629 | bparams->norm = VIDEO_MODE_NTSC; | 1629 | bparams->norm = VIDEO_MODE_NTSC; |
1630 | else if (zr->norm & V4L2_STD_PAL) | 1630 | else if (zr->norm & V4L2_STD_PAL) |
1631 | bparams->norm = VIDEO_MODE_PAL; | 1631 | bparams->norm = VIDEO_MODE_PAL; |
1632 | else | 1632 | else |
1633 | bparams->norm = VIDEO_MODE_SECAM; | 1633 | bparams->norm = VIDEO_MODE_SECAM; |
1634 | 1634 | ||
1635 | bparams->input = zr->input; | 1635 | bparams->input = zr->input; |
1636 | 1636 | ||
1637 | bparams->decimation = fh->jpg_settings.decimation; | 1637 | bparams->decimation = fh->jpg_settings.decimation; |
1638 | bparams->HorDcm = fh->jpg_settings.HorDcm; | 1638 | bparams->HorDcm = fh->jpg_settings.HorDcm; |
1639 | bparams->VerDcm = fh->jpg_settings.VerDcm; | 1639 | bparams->VerDcm = fh->jpg_settings.VerDcm; |
1640 | bparams->TmpDcm = fh->jpg_settings.TmpDcm; | 1640 | bparams->TmpDcm = fh->jpg_settings.TmpDcm; |
1641 | bparams->field_per_buff = fh->jpg_settings.field_per_buff; | 1641 | bparams->field_per_buff = fh->jpg_settings.field_per_buff; |
1642 | bparams->img_x = fh->jpg_settings.img_x; | 1642 | bparams->img_x = fh->jpg_settings.img_x; |
1643 | bparams->img_y = fh->jpg_settings.img_y; | 1643 | bparams->img_y = fh->jpg_settings.img_y; |
1644 | bparams->img_width = fh->jpg_settings.img_width; | 1644 | bparams->img_width = fh->jpg_settings.img_width; |
1645 | bparams->img_height = fh->jpg_settings.img_height; | 1645 | bparams->img_height = fh->jpg_settings.img_height; |
1646 | bparams->odd_even = fh->jpg_settings.odd_even; | 1646 | bparams->odd_even = fh->jpg_settings.odd_even; |
1647 | 1647 | ||
1648 | bparams->quality = fh->jpg_settings.jpg_comp.quality; | 1648 | bparams->quality = fh->jpg_settings.jpg_comp.quality; |
1649 | bparams->APPn = fh->jpg_settings.jpg_comp.APPn; | 1649 | bparams->APPn = fh->jpg_settings.jpg_comp.APPn; |
1650 | bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len; | 1650 | bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len; |
1651 | memcpy(bparams->APP_data, | 1651 | memcpy(bparams->APP_data, |
1652 | fh->jpg_settings.jpg_comp.APP_data, | 1652 | fh->jpg_settings.jpg_comp.APP_data, |
1653 | sizeof(bparams->APP_data)); | 1653 | sizeof(bparams->APP_data)); |
1654 | bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len; | 1654 | bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len; |
1655 | memcpy(bparams->COM_data, | 1655 | memcpy(bparams->COM_data, |
1656 | fh->jpg_settings.jpg_comp.COM_data, | 1656 | fh->jpg_settings.jpg_comp.COM_data, |
1657 | sizeof(bparams->COM_data)); | 1657 | sizeof(bparams->COM_data)); |
1658 | bparams->jpeg_markers = | 1658 | bparams->jpeg_markers = |
1659 | fh->jpg_settings.jpg_comp.jpeg_markers; | 1659 | fh->jpg_settings.jpg_comp.jpeg_markers; |
1660 | 1660 | ||
1661 | mutex_unlock(&zr->resource_lock); | 1661 | mutex_unlock(&zr->resource_lock); |
1662 | 1662 | ||
1663 | bparams->VFIFO_FB = 0; | 1663 | bparams->VFIFO_FB = 0; |
1664 | 1664 | ||
1665 | return 0; | 1665 | return 0; |
1666 | } | 1666 | } |
1667 | 1667 | ||
1668 | case BUZIOC_S_PARAMS: | 1668 | case BUZIOC_S_PARAMS: |
1669 | { | 1669 | { |
1670 | struct zoran_params *bparams = arg; | 1670 | struct zoran_params *bparams = arg; |
1671 | int res = 0; | 1671 | int res = 0; |
1672 | 1672 | ||
1673 | dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr)); | 1673 | dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr)); |
1674 | 1674 | ||
1675 | settings.decimation = bparams->decimation; | 1675 | settings.decimation = bparams->decimation; |
1676 | settings.HorDcm = bparams->HorDcm; | 1676 | settings.HorDcm = bparams->HorDcm; |
1677 | settings.VerDcm = bparams->VerDcm; | 1677 | settings.VerDcm = bparams->VerDcm; |
1678 | settings.TmpDcm = bparams->TmpDcm; | 1678 | settings.TmpDcm = bparams->TmpDcm; |
1679 | settings.field_per_buff = bparams->field_per_buff; | 1679 | settings.field_per_buff = bparams->field_per_buff; |
1680 | settings.img_x = bparams->img_x; | 1680 | settings.img_x = bparams->img_x; |
1681 | settings.img_y = bparams->img_y; | 1681 | settings.img_y = bparams->img_y; |
1682 | settings.img_width = bparams->img_width; | 1682 | settings.img_width = bparams->img_width; |
1683 | settings.img_height = bparams->img_height; | 1683 | settings.img_height = bparams->img_height; |
1684 | settings.odd_even = bparams->odd_even; | 1684 | settings.odd_even = bparams->odd_even; |
1685 | 1685 | ||
1686 | settings.jpg_comp.quality = bparams->quality; | 1686 | settings.jpg_comp.quality = bparams->quality; |
1687 | settings.jpg_comp.APPn = bparams->APPn; | 1687 | settings.jpg_comp.APPn = bparams->APPn; |
1688 | settings.jpg_comp.APP_len = bparams->APP_len; | 1688 | settings.jpg_comp.APP_len = bparams->APP_len; |
1689 | memcpy(settings.jpg_comp.APP_data, bparams->APP_data, | 1689 | memcpy(settings.jpg_comp.APP_data, bparams->APP_data, |
1690 | sizeof(bparams->APP_data)); | 1690 | sizeof(bparams->APP_data)); |
1691 | settings.jpg_comp.COM_len = bparams->COM_len; | 1691 | settings.jpg_comp.COM_len = bparams->COM_len; |
1692 | memcpy(settings.jpg_comp.COM_data, bparams->COM_data, | 1692 | memcpy(settings.jpg_comp.COM_data, bparams->COM_data, |
1693 | sizeof(bparams->COM_data)); | 1693 | sizeof(bparams->COM_data)); |
1694 | settings.jpg_comp.jpeg_markers = bparams->jpeg_markers; | 1694 | settings.jpg_comp.jpeg_markers = bparams->jpeg_markers; |
1695 | 1695 | ||
1696 | mutex_lock(&zr->resource_lock); | 1696 | mutex_lock(&zr->resource_lock); |
1697 | 1697 | ||
1698 | if (zr->codec_mode != BUZ_MODE_IDLE) { | 1698 | if (zr->codec_mode != BUZ_MODE_IDLE) { |
1699 | dprintk(1, | 1699 | dprintk(1, |
1700 | KERN_ERR | 1700 | KERN_ERR |
1701 | "%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n", | 1701 | "%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n", |
1702 | ZR_DEVNAME(zr)); | 1702 | ZR_DEVNAME(zr)); |
1703 | res = -EINVAL; | 1703 | res = -EINVAL; |
1704 | goto sparams_unlock_and_return; | 1704 | goto sparams_unlock_and_return; |
1705 | } | 1705 | } |
1706 | 1706 | ||
1707 | /* Check the params first before overwriting our | 1707 | /* Check the params first before overwriting our |
1708 | * nternal values */ | 1708 | * nternal values */ |
1709 | if (zoran_check_jpg_settings(zr, &settings, 0)) { | 1709 | if (zoran_check_jpg_settings(zr, &settings, 0)) { |
1710 | res = -EINVAL; | 1710 | res = -EINVAL; |
1711 | goto sparams_unlock_and_return; | 1711 | goto sparams_unlock_and_return; |
1712 | } | 1712 | } |
1713 | 1713 | ||
1714 | fh->jpg_settings = settings; | 1714 | fh->jpg_settings = settings; |
1715 | sparams_unlock_and_return: | 1715 | sparams_unlock_and_return: |
1716 | mutex_unlock(&zr->resource_lock); | 1716 | mutex_unlock(&zr->resource_lock); |
1717 | 1717 | ||
1718 | return res; | 1718 | return res; |
1719 | } | 1719 | } |
1720 | 1720 | ||
1721 | case BUZIOC_REQBUFS: | 1721 | case BUZIOC_REQBUFS: |
1722 | { | 1722 | { |
1723 | struct zoran_requestbuffers *breq = arg; | 1723 | struct zoran_requestbuffers *breq = arg; |
1724 | int res = 0; | 1724 | int res = 0; |
1725 | 1725 | ||
1726 | dprintk(3, | 1726 | dprintk(3, |
1727 | KERN_DEBUG | 1727 | KERN_DEBUG |
1728 | "%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n", | 1728 | "%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n", |
1729 | ZR_DEVNAME(zr), breq->count, breq->size); | 1729 | ZR_DEVNAME(zr), breq->count, breq->size); |
1730 | 1730 | ||
1731 | /* Enforce reasonable lower and upper limits */ | 1731 | /* Enforce reasonable lower and upper limits */ |
1732 | if (breq->count < 4) | 1732 | if (breq->count < 4) |
1733 | breq->count = 4; /* Could be choosen smaller */ | 1733 | breq->count = 4; /* Could be choosen smaller */ |
1734 | if (breq->count > jpg_nbufs) | 1734 | if (breq->count > jpg_nbufs) |
1735 | breq->count = jpg_nbufs; | 1735 | breq->count = jpg_nbufs; |
1736 | breq->size = PAGE_ALIGN(breq->size); | 1736 | breq->size = PAGE_ALIGN(breq->size); |
1737 | if (breq->size < 8192) | 1737 | if (breq->size < 8192) |
1738 | breq->size = 8192; /* Arbitrary */ | 1738 | breq->size = 8192; /* Arbitrary */ |
1739 | /* breq->size is limited by 1 page for the stat_com | 1739 | /* breq->size is limited by 1 page for the stat_com |
1740 | * tables to a Maximum of 2 MB */ | 1740 | * tables to a Maximum of 2 MB */ |
1741 | if (breq->size > jpg_bufsize) | 1741 | if (breq->size > jpg_bufsize) |
1742 | breq->size = jpg_bufsize; | 1742 | breq->size = jpg_bufsize; |
1743 | 1743 | ||
1744 | mutex_lock(&zr->resource_lock); | 1744 | mutex_lock(&zr->resource_lock); |
1745 | 1745 | ||
1746 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { | 1746 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { |
1747 | dprintk(1, | 1747 | dprintk(1, |
1748 | KERN_ERR | 1748 | KERN_ERR |
1749 | "%s: BUZIOC_REQBUFS - buffers already allocated\n", | 1749 | "%s: BUZIOC_REQBUFS - buffers already allocated\n", |
1750 | ZR_DEVNAME(zr)); | 1750 | ZR_DEVNAME(zr)); |
1751 | res = -EBUSY; | 1751 | res = -EBUSY; |
1752 | goto jpgreqbuf_unlock_and_return; | 1752 | goto jpgreqbuf_unlock_and_return; |
1753 | } | 1753 | } |
1754 | 1754 | ||
1755 | fh->jpg_buffers.num_buffers = breq->count; | 1755 | fh->jpg_buffers.num_buffers = breq->count; |
1756 | fh->jpg_buffers.buffer_size = breq->size; | 1756 | fh->jpg_buffers.buffer_size = breq->size; |
1757 | 1757 | ||
1758 | if (jpg_fbuffer_alloc(file)) { | 1758 | if (jpg_fbuffer_alloc(file)) { |
1759 | res = -ENOMEM; | 1759 | res = -ENOMEM; |
1760 | goto jpgreqbuf_unlock_and_return; | 1760 | goto jpgreqbuf_unlock_and_return; |
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | /* The next mmap will map the MJPEG buffers - could | 1763 | /* The next mmap will map the MJPEG buffers - could |
1764 | * also be *_PLAY, but it doesn't matter here */ | 1764 | * also be *_PLAY, but it doesn't matter here */ |
1765 | fh->map_mode = ZORAN_MAP_MODE_JPG_REC; | 1765 | fh->map_mode = ZORAN_MAP_MODE_JPG_REC; |
1766 | jpgreqbuf_unlock_and_return: | 1766 | jpgreqbuf_unlock_and_return: |
1767 | mutex_unlock(&zr->resource_lock); | 1767 | mutex_unlock(&zr->resource_lock); |
1768 | 1768 | ||
1769 | return res; | 1769 | return res; |
1770 | } | 1770 | } |
1771 | 1771 | ||
1772 | case BUZIOC_QBUF_CAPT: | 1772 | case BUZIOC_QBUF_CAPT: |
1773 | { | 1773 | { |
1774 | int *frame = arg, res; | 1774 | int *frame = arg, res; |
1775 | 1775 | ||
1776 | dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n", | 1776 | dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n", |
1777 | ZR_DEVNAME(zr), *frame); | 1777 | ZR_DEVNAME(zr), *frame); |
1778 | 1778 | ||
1779 | mutex_lock(&zr->resource_lock); | 1779 | mutex_lock(&zr->resource_lock); |
1780 | res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS); | 1780 | res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS); |
1781 | mutex_unlock(&zr->resource_lock); | 1781 | mutex_unlock(&zr->resource_lock); |
1782 | 1782 | ||
1783 | return res; | 1783 | return res; |
1784 | } | 1784 | } |
1785 | 1785 | ||
1786 | case BUZIOC_QBUF_PLAY: | 1786 | case BUZIOC_QBUF_PLAY: |
1787 | { | 1787 | { |
1788 | int *frame = arg, res; | 1788 | int *frame = arg, res; |
1789 | 1789 | ||
1790 | dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n", | 1790 | dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n", |
1791 | ZR_DEVNAME(zr), *frame); | 1791 | ZR_DEVNAME(zr), *frame); |
1792 | 1792 | ||
1793 | mutex_lock(&zr->resource_lock); | 1793 | mutex_lock(&zr->resource_lock); |
1794 | res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS); | 1794 | res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS); |
1795 | mutex_unlock(&zr->resource_lock); | 1795 | mutex_unlock(&zr->resource_lock); |
1796 | 1796 | ||
1797 | return res; | 1797 | return res; |
1798 | } | 1798 | } |
1799 | 1799 | ||
1800 | case BUZIOC_SYNC: | 1800 | case BUZIOC_SYNC: |
1801 | { | 1801 | { |
1802 | struct zoran_sync *bsync = arg; | 1802 | struct zoran_sync *bsync = arg; |
1803 | int res; | 1803 | int res; |
1804 | 1804 | ||
1805 | dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr)); | 1805 | dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr)); |
1806 | 1806 | ||
1807 | mutex_lock(&zr->resource_lock); | 1807 | mutex_lock(&zr->resource_lock); |
1808 | res = jpg_sync(file, bsync); | 1808 | res = jpg_sync(file, bsync); |
1809 | mutex_unlock(&zr->resource_lock); | 1809 | mutex_unlock(&zr->resource_lock); |
1810 | 1810 | ||
1811 | return res; | 1811 | return res; |
1812 | } | 1812 | } |
1813 | 1813 | ||
1814 | case BUZIOC_G_STATUS: | 1814 | case BUZIOC_G_STATUS: |
1815 | { | 1815 | { |
1816 | struct zoran_status *bstat = arg; | 1816 | struct zoran_status *bstat = arg; |
1817 | struct v4l2_routing route = { 0, 0 }; | 1817 | struct v4l2_routing route = { 0, 0 }; |
1818 | int status = 0, res = 0; | 1818 | int status = 0, res = 0; |
1819 | v4l2_std_id norm; | 1819 | v4l2_std_id norm; |
1820 | 1820 | ||
1821 | dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr)); | 1821 | dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr)); |
1822 | 1822 | ||
1823 | if (zr->codec_mode != BUZ_MODE_IDLE) { | 1823 | if (zr->codec_mode != BUZ_MODE_IDLE) { |
1824 | dprintk(1, | 1824 | dprintk(1, |
1825 | KERN_ERR | 1825 | KERN_ERR |
1826 | "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n", | 1826 | "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n", |
1827 | ZR_DEVNAME(zr)); | 1827 | ZR_DEVNAME(zr)); |
1828 | return -EINVAL; | 1828 | return -EINVAL; |
1829 | } | 1829 | } |
1830 | 1830 | ||
1831 | route.input = zr->card.input[bstat->input].muxsel; | 1831 | route.input = zr->card.input[bstat->input].muxsel; |
1832 | 1832 | ||
1833 | mutex_lock(&zr->resource_lock); | 1833 | mutex_lock(&zr->resource_lock); |
1834 | 1834 | ||
1835 | if (zr->codec_mode != BUZ_MODE_IDLE) { | 1835 | if (zr->codec_mode != BUZ_MODE_IDLE) { |
1836 | dprintk(1, | 1836 | dprintk(1, |
1837 | KERN_ERR | 1837 | KERN_ERR |
1838 | "%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n", | 1838 | "%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n", |
1839 | ZR_DEVNAME(zr)); | 1839 | ZR_DEVNAME(zr)); |
1840 | res = -EINVAL; | 1840 | res = -EINVAL; |
1841 | goto gstat_unlock_and_return; | 1841 | goto gstat_unlock_and_return; |
1842 | } | 1842 | } |
1843 | 1843 | ||
1844 | decoder_s_routing(zr, &route); | 1844 | decoder_s_routing(zr, &route); |
1845 | 1845 | ||
1846 | /* sleep 1 second */ | 1846 | /* sleep 1 second */ |
1847 | ssleep(1); | 1847 | ssleep(1); |
1848 | 1848 | ||
1849 | /* Get status of video decoder */ | 1849 | /* Get status of video decoder */ |
1850 | decoder_call(zr, video, querystd, &norm); | 1850 | decoder_call(zr, video, querystd, &norm); |
1851 | decoder_call(zr, video, g_input_status, &status); | 1851 | decoder_call(zr, video, g_input_status, &status); |
1852 | 1852 | ||
1853 | /* restore previous input and norm */ | 1853 | /* restore previous input and norm */ |
1854 | route.input = zr->card.input[zr->input].muxsel; | 1854 | route.input = zr->card.input[zr->input].muxsel; |
1855 | decoder_s_routing(zr, &route); | 1855 | decoder_s_routing(zr, &route); |
1856 | gstat_unlock_and_return: | 1856 | gstat_unlock_and_return: |
1857 | mutex_unlock(&zr->resource_lock); | 1857 | mutex_unlock(&zr->resource_lock); |
1858 | 1858 | ||
1859 | if (!res) { | 1859 | if (!res) { |
1860 | bstat->signal = | 1860 | bstat->signal = |
1861 | (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1; | 1861 | (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1; |
1862 | if (norm & V4L2_STD_NTSC) | 1862 | if (norm & V4L2_STD_NTSC) |
1863 | bstat->norm = VIDEO_MODE_NTSC; | 1863 | bstat->norm = VIDEO_MODE_NTSC; |
1864 | else if (norm & V4L2_STD_SECAM) | 1864 | else if (norm & V4L2_STD_SECAM) |
1865 | bstat->norm = VIDEO_MODE_SECAM; | 1865 | bstat->norm = VIDEO_MODE_SECAM; |
1866 | else | 1866 | else |
1867 | bstat->norm = VIDEO_MODE_PAL; | 1867 | bstat->norm = VIDEO_MODE_PAL; |
1868 | 1868 | ||
1869 | bstat->color = | 1869 | bstat->color = |
1870 | (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1; | 1870 | (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1; |
1871 | } | 1871 | } |
1872 | 1872 | ||
1873 | return res; | 1873 | return res; |
1874 | } | 1874 | } |
1875 | 1875 | ||
1876 | default: | 1876 | default: |
1877 | return -EINVAL; | 1877 | return -EINVAL; |
1878 | } | 1878 | } |
1879 | } | 1879 | } |
1880 | 1880 | ||
1881 | static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf) | 1881 | static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf) |
1882 | { | 1882 | { |
1883 | struct zoran_fh *fh = __fh; | 1883 | struct zoran_fh *fh = __fh; |
1884 | struct zoran *zr = fh->zr; | 1884 | struct zoran *zr = fh->zr; |
1885 | int i, res = 0; | 1885 | int i, res = 0; |
1886 | 1886 | ||
1887 | vmbuf->size = | 1887 | vmbuf->size = |
1888 | fh->v4l_buffers.num_buffers * | 1888 | fh->v4l_buffers.num_buffers * |
1889 | fh->v4l_buffers.buffer_size; | 1889 | fh->v4l_buffers.buffer_size; |
1890 | vmbuf->frames = fh->v4l_buffers.num_buffers; | 1890 | vmbuf->frames = fh->v4l_buffers.num_buffers; |
1891 | for (i = 0; i < vmbuf->frames; i++) { | 1891 | for (i = 0; i < vmbuf->frames; i++) { |
1892 | vmbuf->offsets[i] = | 1892 | vmbuf->offsets[i] = |
1893 | i * fh->v4l_buffers.buffer_size; | 1893 | i * fh->v4l_buffers.buffer_size; |
1894 | } | 1894 | } |
1895 | 1895 | ||
1896 | mutex_lock(&zr->resource_lock); | 1896 | mutex_lock(&zr->resource_lock); |
1897 | 1897 | ||
1898 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { | 1898 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { |
1899 | dprintk(1, | 1899 | dprintk(1, |
1900 | KERN_ERR | 1900 | KERN_ERR |
1901 | "%s: VIDIOCGMBUF - buffers already allocated\n", | 1901 | "%s: VIDIOCGMBUF - buffers already allocated\n", |
1902 | ZR_DEVNAME(zr)); | 1902 | ZR_DEVNAME(zr)); |
1903 | res = -EINVAL; | 1903 | res = -EINVAL; |
1904 | goto v4l1reqbuf_unlock_and_return; | 1904 | goto v4l1reqbuf_unlock_and_return; |
1905 | } | 1905 | } |
1906 | 1906 | ||
1907 | if (v4l_fbuffer_alloc(file)) { | 1907 | if (v4l_fbuffer_alloc(file)) { |
1908 | res = -ENOMEM; | 1908 | res = -ENOMEM; |
1909 | goto v4l1reqbuf_unlock_and_return; | 1909 | goto v4l1reqbuf_unlock_and_return; |
1910 | } | 1910 | } |
1911 | 1911 | ||
1912 | /* The next mmap will map the V4L buffers */ | 1912 | /* The next mmap will map the V4L buffers */ |
1913 | fh->map_mode = ZORAN_MAP_MODE_RAW; | 1913 | fh->map_mode = ZORAN_MAP_MODE_RAW; |
1914 | v4l1reqbuf_unlock_and_return: | 1914 | v4l1reqbuf_unlock_and_return: |
1915 | mutex_unlock(&zr->resource_lock); | 1915 | mutex_unlock(&zr->resource_lock); |
1916 | 1916 | ||
1917 | return res; | 1917 | return res; |
1918 | } | 1918 | } |
1919 | #endif | 1919 | #endif |
1920 | 1920 | ||
1921 | static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) | 1921 | static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) |
1922 | { | 1922 | { |
1923 | struct zoran_fh *fh = __fh; | 1923 | struct zoran_fh *fh = __fh; |
1924 | struct zoran *zr = fh->zr; | 1924 | struct zoran *zr = fh->zr; |
1925 | 1925 | ||
1926 | memset(cap, 0, sizeof(*cap)); | 1926 | memset(cap, 0, sizeof(*cap)); |
1927 | strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1); | 1927 | strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1); |
1928 | strncpy(cap->driver, "zoran", sizeof(cap->driver)-1); | 1928 | strncpy(cap->driver, "zoran", sizeof(cap->driver)-1); |
1929 | snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", | 1929 | snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", |
1930 | pci_name(zr->pci_dev)); | 1930 | pci_name(zr->pci_dev)); |
1931 | cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION, | 1931 | cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION, |
1932 | RELEASE_VERSION); | 1932 | RELEASE_VERSION); |
1933 | cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | | 1933 | cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | |
1934 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY; | 1934 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY; |
1935 | return 0; | 1935 | return 0; |
1936 | } | 1936 | } |
1937 | 1937 | ||
1938 | static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) | 1938 | static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) |
1939 | { | 1939 | { |
1940 | int num = -1, i; | 1940 | int num = -1, i; |
1941 | 1941 | ||
1942 | for (i = 0; i < NUM_FORMATS; i++) { | 1942 | for (i = 0; i < NUM_FORMATS; i++) { |
1943 | if (zoran_formats[i].flags & flag) | 1943 | if (zoran_formats[i].flags & flag) |
1944 | num++; | 1944 | num++; |
1945 | if (num == fmt->index) | 1945 | if (num == fmt->index) |
1946 | break; | 1946 | break; |
1947 | } | 1947 | } |
1948 | if (fmt->index < 0 /* late, but not too late */ || i == NUM_FORMATS) | 1948 | if (fmt->index < 0 /* late, but not too late */ || i == NUM_FORMATS) |
1949 | return -EINVAL; | 1949 | return -EINVAL; |
1950 | 1950 | ||
1951 | strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1); | 1951 | strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1); |
1952 | fmt->pixelformat = zoran_formats[i].fourcc; | 1952 | fmt->pixelformat = zoran_formats[i].fourcc; |
1953 | if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) | 1953 | if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) |
1954 | fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; | 1954 | fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; |
1955 | return 0; | 1955 | return 0; |
1956 | } | 1956 | } |
1957 | 1957 | ||
1958 | static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, | 1958 | static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, |
1959 | struct v4l2_fmtdesc *f) | 1959 | struct v4l2_fmtdesc *f) |
1960 | { | 1960 | { |
1961 | struct zoran_fh *fh = __fh; | 1961 | struct zoran_fh *fh = __fh; |
1962 | struct zoran *zr = fh->zr; | 1962 | struct zoran *zr = fh->zr; |
1963 | 1963 | ||
1964 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); | 1964 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); |
1965 | } | 1965 | } |
1966 | 1966 | ||
1967 | static int zoran_enum_fmt_vid_out(struct file *file, void *__fh, | 1967 | static int zoran_enum_fmt_vid_out(struct file *file, void *__fh, |
1968 | struct v4l2_fmtdesc *f) | 1968 | struct v4l2_fmtdesc *f) |
1969 | { | 1969 | { |
1970 | struct zoran_fh *fh = __fh; | 1970 | struct zoran_fh *fh = __fh; |
1971 | struct zoran *zr = fh->zr; | 1971 | struct zoran *zr = fh->zr; |
1972 | 1972 | ||
1973 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK); | 1973 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK); |
1974 | } | 1974 | } |
1975 | 1975 | ||
1976 | static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh, | 1976 | static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh, |
1977 | struct v4l2_fmtdesc *f) | 1977 | struct v4l2_fmtdesc *f) |
1978 | { | 1978 | { |
1979 | struct zoran_fh *fh = __fh; | 1979 | struct zoran_fh *fh = __fh; |
1980 | struct zoran *zr = fh->zr; | 1980 | struct zoran *zr = fh->zr; |
1981 | 1981 | ||
1982 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY); | 1982 | return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY); |
1983 | } | 1983 | } |
1984 | 1984 | ||
1985 | static int zoran_g_fmt_vid_out(struct file *file, void *__fh, | 1985 | static int zoran_g_fmt_vid_out(struct file *file, void *__fh, |
1986 | struct v4l2_format *fmt) | 1986 | struct v4l2_format *fmt) |
1987 | { | 1987 | { |
1988 | struct zoran_fh *fh = __fh; | 1988 | struct zoran_fh *fh = __fh; |
1989 | struct zoran *zr = fh->zr; | 1989 | struct zoran *zr = fh->zr; |
1990 | 1990 | ||
1991 | mutex_lock(&zr->resource_lock); | 1991 | mutex_lock(&zr->resource_lock); |
1992 | 1992 | ||
1993 | fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm; | 1993 | fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm; |
1994 | fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 / | 1994 | fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 / |
1995 | (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm); | 1995 | (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm); |
1996 | fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings); | 1996 | fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings); |
1997 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; | 1997 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; |
1998 | if (fh->jpg_settings.TmpDcm == 1) | 1998 | if (fh->jpg_settings.TmpDcm == 1) |
1999 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 1999 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2000 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); | 2000 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
2001 | else | 2001 | else |
2002 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 2002 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2003 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); | 2003 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
2004 | fmt->fmt.pix.bytesperline = 0; | 2004 | fmt->fmt.pix.bytesperline = 0; |
2005 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 2005 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
2006 | 2006 | ||
2007 | mutex_unlock(&zr->resource_lock); | 2007 | mutex_unlock(&zr->resource_lock); |
2008 | return 0; | 2008 | return 0; |
2009 | } | 2009 | } |
2010 | 2010 | ||
2011 | static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, | 2011 | static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, |
2012 | struct v4l2_format *fmt) | 2012 | struct v4l2_format *fmt) |
2013 | { | 2013 | { |
2014 | struct zoran_fh *fh = __fh; | 2014 | struct zoran_fh *fh = __fh; |
2015 | struct zoran *zr = fh->zr; | 2015 | struct zoran *zr = fh->zr; |
2016 | 2016 | ||
2017 | if (fh->map_mode != ZORAN_MAP_MODE_RAW) | 2017 | if (fh->map_mode != ZORAN_MAP_MODE_RAW) |
2018 | return zoran_g_fmt_vid_out(file, fh, fmt); | 2018 | return zoran_g_fmt_vid_out(file, fh, fmt); |
2019 | 2019 | ||
2020 | mutex_lock(&zr->resource_lock); | 2020 | mutex_lock(&zr->resource_lock); |
2021 | fmt->fmt.pix.width = fh->v4l_settings.width; | 2021 | fmt->fmt.pix.width = fh->v4l_settings.width; |
2022 | fmt->fmt.pix.height = fh->v4l_settings.height; | 2022 | fmt->fmt.pix.height = fh->v4l_settings.height; |
2023 | fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline * | 2023 | fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline * |
2024 | fh->v4l_settings.height; | 2024 | fh->v4l_settings.height; |
2025 | fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc; | 2025 | fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc; |
2026 | fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; | 2026 | fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; |
2027 | fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; | 2027 | fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; |
2028 | if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) | 2028 | if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) |
2029 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | 2029 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
2030 | else | 2030 | else |
2031 | fmt->fmt.pix.field = V4L2_FIELD_TOP; | 2031 | fmt->fmt.pix.field = V4L2_FIELD_TOP; |
2032 | mutex_unlock(&zr->resource_lock); | 2032 | mutex_unlock(&zr->resource_lock); |
2033 | return 0; | 2033 | return 0; |
2034 | } | 2034 | } |
2035 | 2035 | ||
2036 | static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh, | 2036 | static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh, |
2037 | struct v4l2_format *fmt) | 2037 | struct v4l2_format *fmt) |
2038 | { | 2038 | { |
2039 | struct zoran_fh *fh = __fh; | 2039 | struct zoran_fh *fh = __fh; |
2040 | struct zoran *zr = fh->zr; | 2040 | struct zoran *zr = fh->zr; |
2041 | 2041 | ||
2042 | mutex_lock(&zr->resource_lock); | 2042 | mutex_lock(&zr->resource_lock); |
2043 | 2043 | ||
2044 | fmt->fmt.win.w.left = fh->overlay_settings.x; | 2044 | fmt->fmt.win.w.left = fh->overlay_settings.x; |
2045 | fmt->fmt.win.w.top = fh->overlay_settings.y; | 2045 | fmt->fmt.win.w.top = fh->overlay_settings.y; |
2046 | fmt->fmt.win.w.width = fh->overlay_settings.width; | 2046 | fmt->fmt.win.w.width = fh->overlay_settings.width; |
2047 | fmt->fmt.win.w.height = fh->overlay_settings.height; | 2047 | fmt->fmt.win.w.height = fh->overlay_settings.height; |
2048 | if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT) | 2048 | if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT) |
2049 | fmt->fmt.win.field = V4L2_FIELD_INTERLACED; | 2049 | fmt->fmt.win.field = V4L2_FIELD_INTERLACED; |
2050 | else | 2050 | else |
2051 | fmt->fmt.win.field = V4L2_FIELD_TOP; | 2051 | fmt->fmt.win.field = V4L2_FIELD_TOP; |
2052 | 2052 | ||
2053 | mutex_unlock(&zr->resource_lock); | 2053 | mutex_unlock(&zr->resource_lock); |
2054 | return 0; | 2054 | return 0; |
2055 | } | 2055 | } |
2056 | 2056 | ||
2057 | static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh, | 2057 | static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh, |
2058 | struct v4l2_format *fmt) | 2058 | struct v4l2_format *fmt) |
2059 | { | 2059 | { |
2060 | struct zoran_fh *fh = __fh; | 2060 | struct zoran_fh *fh = __fh; |
2061 | struct zoran *zr = fh->zr; | 2061 | struct zoran *zr = fh->zr; |
2062 | 2062 | ||
2063 | mutex_lock(&zr->resource_lock); | 2063 | mutex_lock(&zr->resource_lock); |
2064 | 2064 | ||
2065 | if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH) | 2065 | if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH) |
2066 | fmt->fmt.win.w.width = BUZ_MAX_WIDTH; | 2066 | fmt->fmt.win.w.width = BUZ_MAX_WIDTH; |
2067 | if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH) | 2067 | if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH) |
2068 | fmt->fmt.win.w.width = BUZ_MIN_WIDTH; | 2068 | fmt->fmt.win.w.width = BUZ_MIN_WIDTH; |
2069 | if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT) | 2069 | if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT) |
2070 | fmt->fmt.win.w.height = BUZ_MAX_HEIGHT; | 2070 | fmt->fmt.win.w.height = BUZ_MAX_HEIGHT; |
2071 | if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT) | 2071 | if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT) |
2072 | fmt->fmt.win.w.height = BUZ_MIN_HEIGHT; | 2072 | fmt->fmt.win.w.height = BUZ_MIN_HEIGHT; |
2073 | 2073 | ||
2074 | mutex_unlock(&zr->resource_lock); | 2074 | mutex_unlock(&zr->resource_lock); |
2075 | return 0; | 2075 | return 0; |
2076 | } | 2076 | } |
2077 | 2077 | ||
2078 | static int zoran_try_fmt_vid_out(struct file *file, void *__fh, | 2078 | static int zoran_try_fmt_vid_out(struct file *file, void *__fh, |
2079 | struct v4l2_format *fmt) | 2079 | struct v4l2_format *fmt) |
2080 | { | 2080 | { |
2081 | struct zoran_fh *fh = __fh; | 2081 | struct zoran_fh *fh = __fh; |
2082 | struct zoran *zr = fh->zr; | 2082 | struct zoran *zr = fh->zr; |
2083 | struct zoran_jpg_settings settings; | 2083 | struct zoran_jpg_settings settings; |
2084 | int res = 0; | 2084 | int res = 0; |
2085 | 2085 | ||
2086 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) | 2086 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) |
2087 | return -EINVAL; | 2087 | return -EINVAL; |
2088 | 2088 | ||
2089 | mutex_lock(&zr->resource_lock); | 2089 | mutex_lock(&zr->resource_lock); |
2090 | settings = fh->jpg_settings; | 2090 | settings = fh->jpg_settings; |
2091 | 2091 | ||
2092 | /* we actually need to set 'real' parameters now */ | 2092 | /* we actually need to set 'real' parameters now */ |
2093 | if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) | 2093 | if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) |
2094 | settings.TmpDcm = 1; | 2094 | settings.TmpDcm = 1; |
2095 | else | 2095 | else |
2096 | settings.TmpDcm = 2; | 2096 | settings.TmpDcm = 2; |
2097 | settings.decimation = 0; | 2097 | settings.decimation = 0; |
2098 | if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) | 2098 | if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) |
2099 | settings.VerDcm = 2; | 2099 | settings.VerDcm = 2; |
2100 | else | 2100 | else |
2101 | settings.VerDcm = 1; | 2101 | settings.VerDcm = 1; |
2102 | if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) | 2102 | if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) |
2103 | settings.HorDcm = 4; | 2103 | settings.HorDcm = 4; |
2104 | else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) | 2104 | else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) |
2105 | settings.HorDcm = 2; | 2105 | settings.HorDcm = 2; |
2106 | else | 2106 | else |
2107 | settings.HorDcm = 1; | 2107 | settings.HorDcm = 1; |
2108 | if (settings.TmpDcm == 1) | 2108 | if (settings.TmpDcm == 1) |
2109 | settings.field_per_buff = 2; | 2109 | settings.field_per_buff = 2; |
2110 | else | 2110 | else |
2111 | settings.field_per_buff = 1; | 2111 | settings.field_per_buff = 1; |
2112 | 2112 | ||
2113 | if (settings.HorDcm > 1) { | 2113 | if (settings.HorDcm > 1) { |
2114 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; | 2114 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; |
2115 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; | 2115 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; |
2116 | } else { | 2116 | } else { |
2117 | settings.img_x = 0; | 2117 | settings.img_x = 0; |
2118 | settings.img_width = BUZ_MAX_WIDTH; | 2118 | settings.img_width = BUZ_MAX_WIDTH; |
2119 | } | 2119 | } |
2120 | 2120 | ||
2121 | /* check */ | 2121 | /* check */ |
2122 | res = zoran_check_jpg_settings(zr, &settings, 1); | 2122 | res = zoran_check_jpg_settings(zr, &settings, 1); |
2123 | if (res) | 2123 | if (res) |
2124 | goto tryfmt_unlock_and_return; | 2124 | goto tryfmt_unlock_and_return; |
2125 | 2125 | ||
2126 | /* tell the user what we actually did */ | 2126 | /* tell the user what we actually did */ |
2127 | fmt->fmt.pix.width = settings.img_width / settings.HorDcm; | 2127 | fmt->fmt.pix.width = settings.img_width / settings.HorDcm; |
2128 | fmt->fmt.pix.height = settings.img_height * 2 / | 2128 | fmt->fmt.pix.height = settings.img_height * 2 / |
2129 | (settings.TmpDcm * settings.VerDcm); | 2129 | (settings.TmpDcm * settings.VerDcm); |
2130 | if (settings.TmpDcm == 1) | 2130 | if (settings.TmpDcm == 1) |
2131 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 2131 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2132 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); | 2132 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
2133 | else | 2133 | else |
2134 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 2134 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2135 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); | 2135 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
2136 | 2136 | ||
2137 | fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); | 2137 | fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); |
2138 | fmt->fmt.pix.bytesperline = 0; | 2138 | fmt->fmt.pix.bytesperline = 0; |
2139 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 2139 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
2140 | tryfmt_unlock_and_return: | 2140 | tryfmt_unlock_and_return: |
2141 | mutex_unlock(&zr->resource_lock); | 2141 | mutex_unlock(&zr->resource_lock); |
2142 | return res; | 2142 | return res; |
2143 | } | 2143 | } |
2144 | 2144 | ||
2145 | static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, | 2145 | static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, |
2146 | struct v4l2_format *fmt) | 2146 | struct v4l2_format *fmt) |
2147 | { | 2147 | { |
2148 | struct zoran_fh *fh = __fh; | 2148 | struct zoran_fh *fh = __fh; |
2149 | struct zoran *zr = fh->zr; | 2149 | struct zoran *zr = fh->zr; |
2150 | int bpp; | 2150 | int bpp; |
2151 | int i; | 2151 | int i; |
2152 | 2152 | ||
2153 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) | 2153 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) |
2154 | return zoran_try_fmt_vid_out(file, fh, fmt); | 2154 | return zoran_try_fmt_vid_out(file, fh, fmt); |
2155 | 2155 | ||
2156 | mutex_lock(&zr->resource_lock); | 2156 | mutex_lock(&zr->resource_lock); |
2157 | 2157 | ||
2158 | for (i = 0; i < NUM_FORMATS; i++) | 2158 | for (i = 0; i < NUM_FORMATS; i++) |
2159 | if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) | 2159 | if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) |
2160 | break; | 2160 | break; |
2161 | 2161 | ||
2162 | if (i == NUM_FORMATS) { | 2162 | if (i == NUM_FORMATS) { |
2163 | mutex_unlock(&zr->resource_lock); | 2163 | mutex_unlock(&zr->resource_lock); |
2164 | return -EINVAL; | 2164 | return -EINVAL; |
2165 | } | 2165 | } |
2166 | 2166 | ||
2167 | bpp = (zoran_formats[i].depth + 7) / 8; | 2167 | bpp = (zoran_formats[i].depth + 7) / 8; |
2168 | fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3); | 2168 | fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3); |
2169 | if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) | 2169 | if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) |
2170 | fmt->fmt.pix.width = BUZ_MAX_WIDTH; | 2170 | fmt->fmt.pix.width = BUZ_MAX_WIDTH; |
2171 | if (fmt->fmt.pix.width < BUZ_MIN_WIDTH) | 2171 | if (fmt->fmt.pix.width < BUZ_MIN_WIDTH) |
2172 | fmt->fmt.pix.width = BUZ_MIN_WIDTH; | 2172 | fmt->fmt.pix.width = BUZ_MIN_WIDTH; |
2173 | if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) | 2173 | if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) |
2174 | fmt->fmt.pix.height = BUZ_MAX_HEIGHT; | 2174 | fmt->fmt.pix.height = BUZ_MAX_HEIGHT; |
2175 | if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT) | 2175 | if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT) |
2176 | fmt->fmt.pix.height = BUZ_MIN_HEIGHT; | 2176 | fmt->fmt.pix.height = BUZ_MIN_HEIGHT; |
2177 | mutex_unlock(&zr->resource_lock); | 2177 | mutex_unlock(&zr->resource_lock); |
2178 | 2178 | ||
2179 | return 0; | 2179 | return 0; |
2180 | } | 2180 | } |
2181 | 2181 | ||
2182 | static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh, | 2182 | static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh, |
2183 | struct v4l2_format *fmt) | 2183 | struct v4l2_format *fmt) |
2184 | { | 2184 | { |
2185 | struct zoran_fh *fh = __fh; | 2185 | struct zoran_fh *fh = __fh; |
2186 | struct zoran *zr = fh->zr; | 2186 | struct zoran *zr = fh->zr; |
2187 | int res; | 2187 | int res; |
2188 | 2188 | ||
2189 | dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n", | 2189 | dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n", |
2190 | fmt->fmt.win.w.left, fmt->fmt.win.w.top, | 2190 | fmt->fmt.win.w.left, fmt->fmt.win.w.top, |
2191 | fmt->fmt.win.w.width, | 2191 | fmt->fmt.win.w.width, |
2192 | fmt->fmt.win.w.height, | 2192 | fmt->fmt.win.w.height, |
2193 | fmt->fmt.win.clipcount, | 2193 | fmt->fmt.win.clipcount, |
2194 | fmt->fmt.win.bitmap); | 2194 | fmt->fmt.win.bitmap); |
2195 | mutex_lock(&zr->resource_lock); | 2195 | mutex_lock(&zr->resource_lock); |
2196 | res = setup_window(file, fmt->fmt.win.w.left, | 2196 | res = setup_window(file, fmt->fmt.win.w.left, |
2197 | fmt->fmt.win.w.top, | 2197 | fmt->fmt.win.w.top, |
2198 | fmt->fmt.win.w.width, | 2198 | fmt->fmt.win.w.width, |
2199 | fmt->fmt.win.w.height, | 2199 | fmt->fmt.win.w.height, |
2200 | (struct v4l2_clip __user *) | 2200 | (struct v4l2_clip __user *) |
2201 | fmt->fmt.win.clips, | 2201 | fmt->fmt.win.clips, |
2202 | fmt->fmt.win.clipcount, | 2202 | fmt->fmt.win.clipcount, |
2203 | fmt->fmt.win.bitmap); | 2203 | fmt->fmt.win.bitmap); |
2204 | mutex_unlock(&zr->resource_lock); | 2204 | mutex_unlock(&zr->resource_lock); |
2205 | return res; | 2205 | return res; |
2206 | } | 2206 | } |
2207 | 2207 | ||
2208 | static int zoran_s_fmt_vid_out(struct file *file, void *__fh, | 2208 | static int zoran_s_fmt_vid_out(struct file *file, void *__fh, |
2209 | struct v4l2_format *fmt) | 2209 | struct v4l2_format *fmt) |
2210 | { | 2210 | { |
2211 | struct zoran_fh *fh = __fh; | 2211 | struct zoran_fh *fh = __fh; |
2212 | struct zoran *zr = fh->zr; | 2212 | struct zoran *zr = fh->zr; |
2213 | __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); | 2213 | __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); |
2214 | struct zoran_jpg_settings settings; | 2214 | struct zoran_jpg_settings settings; |
2215 | int res = 0; | 2215 | int res = 0; |
2216 | 2216 | ||
2217 | dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n", | 2217 | dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n", |
2218 | fmt->fmt.pix.width, fmt->fmt.pix.height, | 2218 | fmt->fmt.pix.width, fmt->fmt.pix.height, |
2219 | fmt->fmt.pix.pixelformat, | 2219 | fmt->fmt.pix.pixelformat, |
2220 | (char *) &printformat); | 2220 | (char *) &printformat); |
2221 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) | 2221 | if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) |
2222 | return -EINVAL; | 2222 | return -EINVAL; |
2223 | 2223 | ||
2224 | mutex_lock(&zr->resource_lock); | 2224 | mutex_lock(&zr->resource_lock); |
2225 | 2225 | ||
2226 | settings = fh->jpg_settings; | 2226 | settings = fh->jpg_settings; |
2227 | 2227 | ||
2228 | if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) { | 2228 | if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) { |
2229 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", | 2229 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", |
2230 | ZR_DEVNAME(zr)); | 2230 | ZR_DEVNAME(zr)); |
2231 | res = -EBUSY; | 2231 | res = -EBUSY; |
2232 | goto sfmtjpg_unlock_and_return; | 2232 | goto sfmtjpg_unlock_and_return; |
2233 | } | 2233 | } |
2234 | 2234 | ||
2235 | /* we actually need to set 'real' parameters now */ | 2235 | /* we actually need to set 'real' parameters now */ |
2236 | if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) | 2236 | if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) |
2237 | settings.TmpDcm = 1; | 2237 | settings.TmpDcm = 1; |
2238 | else | 2238 | else |
2239 | settings.TmpDcm = 2; | 2239 | settings.TmpDcm = 2; |
2240 | settings.decimation = 0; | 2240 | settings.decimation = 0; |
2241 | if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) | 2241 | if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) |
2242 | settings.VerDcm = 2; | 2242 | settings.VerDcm = 2; |
2243 | else | 2243 | else |
2244 | settings.VerDcm = 1; | 2244 | settings.VerDcm = 1; |
2245 | if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) | 2245 | if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) |
2246 | settings.HorDcm = 4; | 2246 | settings.HorDcm = 4; |
2247 | else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) | 2247 | else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) |
2248 | settings.HorDcm = 2; | 2248 | settings.HorDcm = 2; |
2249 | else | 2249 | else |
2250 | settings.HorDcm = 1; | 2250 | settings.HorDcm = 1; |
2251 | if (settings.TmpDcm == 1) | 2251 | if (settings.TmpDcm == 1) |
2252 | settings.field_per_buff = 2; | 2252 | settings.field_per_buff = 2; |
2253 | else | 2253 | else |
2254 | settings.field_per_buff = 1; | 2254 | settings.field_per_buff = 1; |
2255 | 2255 | ||
2256 | if (settings.HorDcm > 1) { | 2256 | if (settings.HorDcm > 1) { |
2257 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; | 2257 | settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; |
2258 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; | 2258 | settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; |
2259 | } else { | 2259 | } else { |
2260 | settings.img_x = 0; | 2260 | settings.img_x = 0; |
2261 | settings.img_width = BUZ_MAX_WIDTH; | 2261 | settings.img_width = BUZ_MAX_WIDTH; |
2262 | } | 2262 | } |
2263 | 2263 | ||
2264 | /* check */ | 2264 | /* check */ |
2265 | res = zoran_check_jpg_settings(zr, &settings, 0); | 2265 | res = zoran_check_jpg_settings(zr, &settings, 0); |
2266 | if (res) | 2266 | if (res) |
2267 | goto sfmtjpg_unlock_and_return; | 2267 | goto sfmtjpg_unlock_and_return; |
2268 | 2268 | ||
2269 | /* it's ok, so set them */ | 2269 | /* it's ok, so set them */ |
2270 | fh->jpg_settings = settings; | 2270 | fh->jpg_settings = settings; |
2271 | 2271 | ||
2272 | /* tell the user what we actually did */ | 2272 | /* tell the user what we actually did */ |
2273 | fmt->fmt.pix.width = settings.img_width / settings.HorDcm; | 2273 | fmt->fmt.pix.width = settings.img_width / settings.HorDcm; |
2274 | fmt->fmt.pix.height = settings.img_height * 2 / | 2274 | fmt->fmt.pix.height = settings.img_height * 2 / |
2275 | (settings.TmpDcm * settings.VerDcm); | 2275 | (settings.TmpDcm * settings.VerDcm); |
2276 | if (settings.TmpDcm == 1) | 2276 | if (settings.TmpDcm == 1) |
2277 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 2277 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2278 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); | 2278 | V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); |
2279 | else | 2279 | else |
2280 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? | 2280 | fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? |
2281 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); | 2281 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); |
2282 | fh->jpg_buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); | 2282 | fh->jpg_buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); |
2283 | fmt->fmt.pix.bytesperline = 0; | 2283 | fmt->fmt.pix.bytesperline = 0; |
2284 | fmt->fmt.pix.sizeimage = fh->jpg_buffers.buffer_size; | 2284 | fmt->fmt.pix.sizeimage = fh->jpg_buffers.buffer_size; |
2285 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 2285 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
2286 | 2286 | ||
2287 | /* we hereby abuse this variable to show that | 2287 | /* we hereby abuse this variable to show that |
2288 | * we're gonna do mjpeg capture */ | 2288 | * we're gonna do mjpeg capture */ |
2289 | fh->map_mode = (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? | 2289 | fh->map_mode = (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? |
2290 | ZORAN_MAP_MODE_JPG_REC : ZORAN_MAP_MODE_JPG_PLAY; | 2290 | ZORAN_MAP_MODE_JPG_REC : ZORAN_MAP_MODE_JPG_PLAY; |
2291 | sfmtjpg_unlock_and_return: | 2291 | sfmtjpg_unlock_and_return: |
2292 | mutex_unlock(&zr->resource_lock); | 2292 | mutex_unlock(&zr->resource_lock); |
2293 | return res; | 2293 | return res; |
2294 | } | 2294 | } |
2295 | 2295 | ||
2296 | static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, | 2296 | static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, |
2297 | struct v4l2_format *fmt) | 2297 | struct v4l2_format *fmt) |
2298 | { | 2298 | { |
2299 | struct zoran_fh *fh = __fh; | 2299 | struct zoran_fh *fh = __fh; |
2300 | struct zoran *zr = fh->zr; | 2300 | struct zoran *zr = fh->zr; |
2301 | int i; | 2301 | int i; |
2302 | int res = 0; | 2302 | int res = 0; |
2303 | 2303 | ||
2304 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) | 2304 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) |
2305 | return zoran_s_fmt_vid_out(file, fh, fmt); | 2305 | return zoran_s_fmt_vid_out(file, fh, fmt); |
2306 | 2306 | ||
2307 | for (i = 0; i < NUM_FORMATS; i++) | 2307 | for (i = 0; i < NUM_FORMATS; i++) |
2308 | if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) | 2308 | if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) |
2309 | break; | 2309 | break; |
2310 | if (i == NUM_FORMATS) { | 2310 | if (i == NUM_FORMATS) { |
2311 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", | 2311 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", |
2312 | ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat); | 2312 | ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat); |
2313 | return -EINVAL; | 2313 | return -EINVAL; |
2314 | } | 2314 | } |
2315 | mutex_lock(&zr->resource_lock); | 2315 | mutex_lock(&zr->resource_lock); |
2316 | if (fh->jpg_buffers.allocated || | 2316 | if (fh->jpg_buffers.allocated || |
2317 | (fh->v4l_buffers.allocated && fh->v4l_buffers.active != ZORAN_FREE)) { | 2317 | (fh->v4l_buffers.allocated && fh->v4l_buffers.active != ZORAN_FREE)) { |
2318 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", | 2318 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", |
2319 | ZR_DEVNAME(zr)); | 2319 | ZR_DEVNAME(zr)); |
2320 | res = -EBUSY; | 2320 | res = -EBUSY; |
2321 | goto sfmtv4l_unlock_and_return; | 2321 | goto sfmtv4l_unlock_and_return; |
2322 | } | 2322 | } |
2323 | if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) | 2323 | if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) |
2324 | fmt->fmt.pix.height = BUZ_MAX_HEIGHT; | 2324 | fmt->fmt.pix.height = BUZ_MAX_HEIGHT; |
2325 | if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) | 2325 | if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) |
2326 | fmt->fmt.pix.width = BUZ_MAX_WIDTH; | 2326 | fmt->fmt.pix.width = BUZ_MAX_WIDTH; |
2327 | 2327 | ||
2328 | res = zoran_v4l_set_format(file, fmt->fmt.pix.width, | 2328 | res = zoran_v4l_set_format(file, fmt->fmt.pix.width, |
2329 | fmt->fmt.pix.height, &zoran_formats[i]); | 2329 | fmt->fmt.pix.height, &zoran_formats[i]); |
2330 | if (res) | 2330 | if (res) |
2331 | goto sfmtv4l_unlock_and_return; | 2331 | goto sfmtv4l_unlock_and_return; |
2332 | 2332 | ||
2333 | /* tell the user the | 2333 | /* tell the user the |
2334 | * results/missing stuff */ | 2334 | * results/missing stuff */ |
2335 | fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; | 2335 | fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; |
2336 | fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline; | 2336 | fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline; |
2337 | fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; | 2337 | fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; |
2338 | if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) | 2338 | if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) |
2339 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | 2339 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
2340 | else | 2340 | else |
2341 | fmt->fmt.pix.field = V4L2_FIELD_TOP; | 2341 | fmt->fmt.pix.field = V4L2_FIELD_TOP; |
2342 | 2342 | ||
2343 | fh->map_mode = ZORAN_MAP_MODE_RAW; | 2343 | fh->map_mode = ZORAN_MAP_MODE_RAW; |
2344 | sfmtv4l_unlock_and_return: | 2344 | sfmtv4l_unlock_and_return: |
2345 | mutex_unlock(&zr->resource_lock); | 2345 | mutex_unlock(&zr->resource_lock); |
2346 | return res; | 2346 | return res; |
2347 | } | 2347 | } |
2348 | 2348 | ||
2349 | static int zoran_g_fbuf(struct file *file, void *__fh, | 2349 | static int zoran_g_fbuf(struct file *file, void *__fh, |
2350 | struct v4l2_framebuffer *fb) | 2350 | struct v4l2_framebuffer *fb) |
2351 | { | 2351 | { |
2352 | struct zoran_fh *fh = __fh; | 2352 | struct zoran_fh *fh = __fh; |
2353 | struct zoran *zr = fh->zr; | 2353 | struct zoran *zr = fh->zr; |
2354 | 2354 | ||
2355 | memset(fb, 0, sizeof(*fb)); | 2355 | memset(fb, 0, sizeof(*fb)); |
2356 | mutex_lock(&zr->resource_lock); | 2356 | mutex_lock(&zr->resource_lock); |
2357 | fb->base = zr->vbuf_base; | 2357 | fb->base = zr->vbuf_base; |
2358 | fb->fmt.width = zr->vbuf_width; | 2358 | fb->fmt.width = zr->vbuf_width; |
2359 | fb->fmt.height = zr->vbuf_height; | 2359 | fb->fmt.height = zr->vbuf_height; |
2360 | if (zr->overlay_settings.format) | 2360 | if (zr->overlay_settings.format) |
2361 | fb->fmt.pixelformat = fh->overlay_settings.format->fourcc; | 2361 | fb->fmt.pixelformat = fh->overlay_settings.format->fourcc; |
2362 | fb->fmt.bytesperline = zr->vbuf_bytesperline; | 2362 | fb->fmt.bytesperline = zr->vbuf_bytesperline; |
2363 | mutex_unlock(&zr->resource_lock); | 2363 | mutex_unlock(&zr->resource_lock); |
2364 | fb->fmt.colorspace = V4L2_COLORSPACE_SRGB; | 2364 | fb->fmt.colorspace = V4L2_COLORSPACE_SRGB; |
2365 | fb->fmt.field = V4L2_FIELD_INTERLACED; | 2365 | fb->fmt.field = V4L2_FIELD_INTERLACED; |
2366 | fb->flags = V4L2_FBUF_FLAG_OVERLAY; | 2366 | fb->flags = V4L2_FBUF_FLAG_OVERLAY; |
2367 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | 2367 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; |
2368 | 2368 | ||
2369 | return 0; | 2369 | return 0; |
2370 | } | 2370 | } |
2371 | 2371 | ||
2372 | static int zoran_s_fbuf(struct file *file, void *__fh, | 2372 | static int zoran_s_fbuf(struct file *file, void *__fh, |
2373 | struct v4l2_framebuffer *fb) | 2373 | struct v4l2_framebuffer *fb) |
2374 | { | 2374 | { |
2375 | struct zoran_fh *fh = __fh; | 2375 | struct zoran_fh *fh = __fh; |
2376 | struct zoran *zr = fh->zr; | 2376 | struct zoran *zr = fh->zr; |
2377 | int i, res = 0; | 2377 | int i, res = 0; |
2378 | __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); | 2378 | __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); |
2379 | 2379 | ||
2380 | for (i = 0; i < NUM_FORMATS; i++) | 2380 | for (i = 0; i < NUM_FORMATS; i++) |
2381 | if (zoran_formats[i].fourcc == fb->fmt.pixelformat) | 2381 | if (zoran_formats[i].fourcc == fb->fmt.pixelformat) |
2382 | break; | 2382 | break; |
2383 | if (i == NUM_FORMATS) { | 2383 | if (i == NUM_FORMATS) { |
2384 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n", | 2384 | dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n", |
2385 | ZR_DEVNAME(zr), fb->fmt.pixelformat, | 2385 | ZR_DEVNAME(zr), fb->fmt.pixelformat, |
2386 | (char *)&printformat); | 2386 | (char *)&printformat); |
2387 | return -EINVAL; | 2387 | return -EINVAL; |
2388 | } | 2388 | } |
2389 | 2389 | ||
2390 | mutex_lock(&zr->resource_lock); | 2390 | mutex_lock(&zr->resource_lock); |
2391 | res = setup_fbuffer(file, fb->base, &zoran_formats[i], | 2391 | res = setup_fbuffer(file, fb->base, &zoran_formats[i], |
2392 | fb->fmt.width, fb->fmt.height, | 2392 | fb->fmt.width, fb->fmt.height, |
2393 | fb->fmt.bytesperline); | 2393 | fb->fmt.bytesperline); |
2394 | mutex_unlock(&zr->resource_lock); | 2394 | mutex_unlock(&zr->resource_lock); |
2395 | 2395 | ||
2396 | return res; | 2396 | return res; |
2397 | } | 2397 | } |
2398 | 2398 | ||
2399 | static int zoran_overlay(struct file *file, void *__fh, unsigned int on) | 2399 | static int zoran_overlay(struct file *file, void *__fh, unsigned int on) |
2400 | { | 2400 | { |
2401 | struct zoran_fh *fh = __fh; | 2401 | struct zoran_fh *fh = __fh; |
2402 | struct zoran *zr = fh->zr; | 2402 | struct zoran *zr = fh->zr; |
2403 | int res; | 2403 | int res; |
2404 | 2404 | ||
2405 | mutex_lock(&zr->resource_lock); | 2405 | mutex_lock(&zr->resource_lock); |
2406 | res = setup_overlay(file, on); | 2406 | res = setup_overlay(file, on); |
2407 | mutex_unlock(&zr->resource_lock); | 2407 | mutex_unlock(&zr->resource_lock); |
2408 | 2408 | ||
2409 | return res; | 2409 | return res; |
2410 | } | 2410 | } |
2411 | 2411 | ||
2412 | static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type); | 2412 | static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type); |
2413 | 2413 | ||
2414 | static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req) | 2414 | static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req) |
2415 | { | 2415 | { |
2416 | struct zoran_fh *fh = __fh; | 2416 | struct zoran_fh *fh = __fh; |
2417 | struct zoran *zr = fh->zr; | 2417 | struct zoran *zr = fh->zr; |
2418 | int res = 0; | 2418 | int res = 0; |
2419 | 2419 | ||
2420 | if (req->memory != V4L2_MEMORY_MMAP) { | 2420 | if (req->memory != V4L2_MEMORY_MMAP) { |
2421 | dprintk(2, | 2421 | dprintk(2, |
2422 | KERN_ERR | 2422 | KERN_ERR |
2423 | "%s: only MEMORY_MMAP capture is supported, not %d\n", | 2423 | "%s: only MEMORY_MMAP capture is supported, not %d\n", |
2424 | ZR_DEVNAME(zr), req->memory); | 2424 | ZR_DEVNAME(zr), req->memory); |
2425 | return -EINVAL; | 2425 | return -EINVAL; |
2426 | } | 2426 | } |
2427 | 2427 | ||
2428 | if (req->count == 0) | 2428 | if (req->count == 0) |
2429 | return zoran_streamoff(file, fh, req->type); | 2429 | return zoran_streamoff(file, fh, req->type); |
2430 | 2430 | ||
2431 | mutex_lock(&zr->resource_lock); | 2431 | mutex_lock(&zr->resource_lock); |
2432 | if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) { | 2432 | if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) { |
2433 | dprintk(2, | 2433 | dprintk(2, |
2434 | KERN_ERR | 2434 | KERN_ERR |
2435 | "%s: VIDIOC_REQBUFS - buffers already allocated\n", | 2435 | "%s: VIDIOC_REQBUFS - buffers already allocated\n", |
2436 | ZR_DEVNAME(zr)); | 2436 | ZR_DEVNAME(zr)); |
2437 | res = -EBUSY; | 2437 | res = -EBUSY; |
2438 | goto v4l2reqbuf_unlock_and_return; | 2438 | goto v4l2reqbuf_unlock_and_return; |
2439 | } | 2439 | } |
2440 | 2440 | ||
2441 | if (fh->map_mode == ZORAN_MAP_MODE_RAW && | 2441 | if (fh->map_mode == ZORAN_MAP_MODE_RAW && |
2442 | req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 2442 | req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
2443 | 2443 | ||
2444 | /* control user input */ | 2444 | /* control user input */ |
2445 | if (req->count < 2) | 2445 | if (req->count < 2) |
2446 | req->count = 2; | 2446 | req->count = 2; |
2447 | if (req->count > v4l_nbufs) | 2447 | if (req->count > v4l_nbufs) |
2448 | req->count = v4l_nbufs; | 2448 | req->count = v4l_nbufs; |
2449 | fh->v4l_buffers.num_buffers = req->count; | 2449 | fh->v4l_buffers.num_buffers = req->count; |
2450 | 2450 | ||
2451 | if (v4l_fbuffer_alloc(file)) { | 2451 | if (v4l_fbuffer_alloc(file)) { |
2452 | res = -ENOMEM; | 2452 | res = -ENOMEM; |
2453 | goto v4l2reqbuf_unlock_and_return; | 2453 | goto v4l2reqbuf_unlock_and_return; |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | /* The next mmap will map the V4L buffers */ | 2456 | /* The next mmap will map the V4L buffers */ |
2457 | fh->map_mode = ZORAN_MAP_MODE_RAW; | 2457 | fh->map_mode = ZORAN_MAP_MODE_RAW; |
2458 | 2458 | ||
2459 | } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC || | 2459 | } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC || |
2460 | fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { | 2460 | fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { |
2461 | 2461 | ||
2462 | /* we need to calculate size ourselves now */ | 2462 | /* we need to calculate size ourselves now */ |
2463 | if (req->count < 4) | 2463 | if (req->count < 4) |
2464 | req->count = 4; | 2464 | req->count = 4; |
2465 | if (req->count > jpg_nbufs) | 2465 | if (req->count > jpg_nbufs) |
2466 | req->count = jpg_nbufs; | 2466 | req->count = jpg_nbufs; |
2467 | fh->jpg_buffers.num_buffers = req->count; | 2467 | fh->jpg_buffers.num_buffers = req->count; |
2468 | fh->jpg_buffers.buffer_size = | 2468 | fh->jpg_buffers.buffer_size = |
2469 | zoran_v4l2_calc_bufsize(&fh->jpg_settings); | 2469 | zoran_v4l2_calc_bufsize(&fh->jpg_settings); |
2470 | 2470 | ||
2471 | if (jpg_fbuffer_alloc(file)) { | 2471 | if (jpg_fbuffer_alloc(file)) { |
2472 | res = -ENOMEM; | 2472 | res = -ENOMEM; |
2473 | goto v4l2reqbuf_unlock_and_return; | 2473 | goto v4l2reqbuf_unlock_and_return; |
2474 | } | 2474 | } |
2475 | 2475 | ||
2476 | /* The next mmap will map the MJPEG buffers */ | 2476 | /* The next mmap will map the MJPEG buffers */ |
2477 | if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2477 | if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2478 | fh->map_mode = ZORAN_MAP_MODE_JPG_REC; | 2478 | fh->map_mode = ZORAN_MAP_MODE_JPG_REC; |
2479 | else | 2479 | else |
2480 | fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY; | 2480 | fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY; |
2481 | 2481 | ||
2482 | } else { | 2482 | } else { |
2483 | dprintk(1, | 2483 | dprintk(1, |
2484 | KERN_ERR | 2484 | KERN_ERR |
2485 | "%s: VIDIOC_REQBUFS - unknown type %d\n", | 2485 | "%s: VIDIOC_REQBUFS - unknown type %d\n", |
2486 | ZR_DEVNAME(zr), req->type); | 2486 | ZR_DEVNAME(zr), req->type); |
2487 | res = -EINVAL; | 2487 | res = -EINVAL; |
2488 | goto v4l2reqbuf_unlock_and_return; | 2488 | goto v4l2reqbuf_unlock_and_return; |
2489 | } | 2489 | } |
2490 | v4l2reqbuf_unlock_and_return: | 2490 | v4l2reqbuf_unlock_and_return: |
2491 | mutex_unlock(&zr->resource_lock); | 2491 | mutex_unlock(&zr->resource_lock); |
2492 | 2492 | ||
2493 | return res; | 2493 | return res; |
2494 | } | 2494 | } |
2495 | 2495 | ||
2496 | static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | 2496 | static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) |
2497 | { | 2497 | { |
2498 | struct zoran_fh *fh = __fh; | 2498 | struct zoran_fh *fh = __fh; |
2499 | struct zoran *zr = fh->zr; | 2499 | struct zoran *zr = fh->zr; |
2500 | int res; | 2500 | int res; |
2501 | 2501 | ||
2502 | mutex_lock(&zr->resource_lock); | 2502 | mutex_lock(&zr->resource_lock); |
2503 | res = zoran_v4l2_buffer_status(fh, buf, buf->index); | 2503 | res = zoran_v4l2_buffer_status(fh, buf, buf->index); |
2504 | mutex_unlock(&zr->resource_lock); | 2504 | mutex_unlock(&zr->resource_lock); |
2505 | 2505 | ||
2506 | return res; | 2506 | return res; |
2507 | } | 2507 | } |
2508 | 2508 | ||
2509 | static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | 2509 | static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) |
2510 | { | 2510 | { |
2511 | struct zoran_fh *fh = __fh; | 2511 | struct zoran_fh *fh = __fh; |
2512 | struct zoran *zr = fh->zr; | 2512 | struct zoran *zr = fh->zr; |
2513 | int res = 0, codec_mode, buf_type; | 2513 | int res = 0, codec_mode, buf_type; |
2514 | 2514 | ||
2515 | mutex_lock(&zr->resource_lock); | 2515 | mutex_lock(&zr->resource_lock); |
2516 | 2516 | ||
2517 | switch (fh->map_mode) { | 2517 | switch (fh->map_mode) { |
2518 | case ZORAN_MAP_MODE_RAW: | 2518 | case ZORAN_MAP_MODE_RAW: |
2519 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 2519 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
2520 | dprintk(1, KERN_ERR | 2520 | dprintk(1, KERN_ERR |
2521 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", | 2521 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", |
2522 | ZR_DEVNAME(zr), buf->type, fh->map_mode); | 2522 | ZR_DEVNAME(zr), buf->type, fh->map_mode); |
2523 | res = -EINVAL; | 2523 | res = -EINVAL; |
2524 | goto qbuf_unlock_and_return; | 2524 | goto qbuf_unlock_and_return; |
2525 | } | 2525 | } |
2526 | 2526 | ||
2527 | res = zoran_v4l_queue_frame(file, buf->index); | 2527 | res = zoran_v4l_queue_frame(file, buf->index); |
2528 | if (res) | 2528 | if (res) |
2529 | goto qbuf_unlock_and_return; | 2529 | goto qbuf_unlock_and_return; |
2530 | if (!zr->v4l_memgrab_active && | 2530 | if (!zr->v4l_memgrab_active && |
2531 | fh->v4l_buffers.active == ZORAN_LOCKED) | 2531 | fh->v4l_buffers.active == ZORAN_LOCKED) |
2532 | zr36057_set_memgrab(zr, 1); | 2532 | zr36057_set_memgrab(zr, 1); |
2533 | break; | 2533 | break; |
2534 | 2534 | ||
2535 | case ZORAN_MAP_MODE_JPG_REC: | 2535 | case ZORAN_MAP_MODE_JPG_REC: |
2536 | case ZORAN_MAP_MODE_JPG_PLAY: | 2536 | case ZORAN_MAP_MODE_JPG_PLAY: |
2537 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { | 2537 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { |
2538 | buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | 2538 | buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
2539 | codec_mode = BUZ_MODE_MOTION_DECOMPRESS; | 2539 | codec_mode = BUZ_MODE_MOTION_DECOMPRESS; |
2540 | } else { | 2540 | } else { |
2541 | buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 2541 | buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
2542 | codec_mode = BUZ_MODE_MOTION_COMPRESS; | 2542 | codec_mode = BUZ_MODE_MOTION_COMPRESS; |
2543 | } | 2543 | } |
2544 | 2544 | ||
2545 | if (buf->type != buf_type) { | 2545 | if (buf->type != buf_type) { |
2546 | dprintk(1, KERN_ERR | 2546 | dprintk(1, KERN_ERR |
2547 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", | 2547 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", |
2548 | ZR_DEVNAME(zr), buf->type, fh->map_mode); | 2548 | ZR_DEVNAME(zr), buf->type, fh->map_mode); |
2549 | res = -EINVAL; | 2549 | res = -EINVAL; |
2550 | goto qbuf_unlock_and_return; | 2550 | goto qbuf_unlock_and_return; |
2551 | } | 2551 | } |
2552 | 2552 | ||
2553 | res = zoran_jpg_queue_frame(file, buf->index, | 2553 | res = zoran_jpg_queue_frame(file, buf->index, |
2554 | codec_mode); | 2554 | codec_mode); |
2555 | if (res != 0) | 2555 | if (res != 0) |
2556 | goto qbuf_unlock_and_return; | 2556 | goto qbuf_unlock_and_return; |
2557 | if (zr->codec_mode == BUZ_MODE_IDLE && | 2557 | if (zr->codec_mode == BUZ_MODE_IDLE && |
2558 | fh->jpg_buffers.active == ZORAN_LOCKED) { | 2558 | fh->jpg_buffers.active == ZORAN_LOCKED) { |
2559 | zr36057_enable_jpg(zr, codec_mode); | 2559 | zr36057_enable_jpg(zr, codec_mode); |
2560 | } | 2560 | } |
2561 | break; | 2561 | break; |
2562 | 2562 | ||
2563 | default: | 2563 | default: |
2564 | dprintk(1, KERN_ERR | 2564 | dprintk(1, KERN_ERR |
2565 | "%s: VIDIOC_QBUF - unsupported type %d\n", | 2565 | "%s: VIDIOC_QBUF - unsupported type %d\n", |
2566 | ZR_DEVNAME(zr), buf->type); | 2566 | ZR_DEVNAME(zr), buf->type); |
2567 | res = -EINVAL; | 2567 | res = -EINVAL; |
2568 | break; | 2568 | break; |
2569 | } | 2569 | } |
2570 | qbuf_unlock_and_return: | 2570 | qbuf_unlock_and_return: |
2571 | mutex_unlock(&zr->resource_lock); | 2571 | mutex_unlock(&zr->resource_lock); |
2572 | 2572 | ||
2573 | return res; | 2573 | return res; |
2574 | } | 2574 | } |
2575 | 2575 | ||
2576 | static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | 2576 | static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) |
2577 | { | 2577 | { |
2578 | struct zoran_fh *fh = __fh; | 2578 | struct zoran_fh *fh = __fh; |
2579 | struct zoran *zr = fh->zr; | 2579 | struct zoran *zr = fh->zr; |
2580 | int res = 0, buf_type, num = -1; /* compiler borks here (?) */ | 2580 | int res = 0, buf_type, num = -1; /* compiler borks here (?) */ |
2581 | 2581 | ||
2582 | mutex_lock(&zr->resource_lock); | 2582 | mutex_lock(&zr->resource_lock); |
2583 | 2583 | ||
2584 | switch (fh->map_mode) { | 2584 | switch (fh->map_mode) { |
2585 | case ZORAN_MAP_MODE_RAW: | 2585 | case ZORAN_MAP_MODE_RAW: |
2586 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 2586 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
2587 | dprintk(1, KERN_ERR | 2587 | dprintk(1, KERN_ERR |
2588 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", | 2588 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", |
2589 | ZR_DEVNAME(zr), buf->type, fh->map_mode); | 2589 | ZR_DEVNAME(zr), buf->type, fh->map_mode); |
2590 | res = -EINVAL; | 2590 | res = -EINVAL; |
2591 | goto dqbuf_unlock_and_return; | 2591 | goto dqbuf_unlock_and_return; |
2592 | } | 2592 | } |
2593 | 2593 | ||
2594 | num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; | 2594 | num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; |
2595 | if (file->f_flags & O_NONBLOCK && | 2595 | if (file->f_flags & O_NONBLOCK && |
2596 | zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) { | 2596 | zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) { |
2597 | res = -EAGAIN; | 2597 | res = -EAGAIN; |
2598 | goto dqbuf_unlock_and_return; | 2598 | goto dqbuf_unlock_and_return; |
2599 | } | 2599 | } |
2600 | res = v4l_sync(file, num); | 2600 | res = v4l_sync(file, num); |
2601 | if (res) | 2601 | if (res) |
2602 | goto dqbuf_unlock_and_return; | 2602 | goto dqbuf_unlock_and_return; |
2603 | zr->v4l_sync_tail++; | 2603 | zr->v4l_sync_tail++; |
2604 | res = zoran_v4l2_buffer_status(fh, buf, num); | 2604 | res = zoran_v4l2_buffer_status(fh, buf, num); |
2605 | break; | 2605 | break; |
2606 | 2606 | ||
2607 | case ZORAN_MAP_MODE_JPG_REC: | 2607 | case ZORAN_MAP_MODE_JPG_REC: |
2608 | case ZORAN_MAP_MODE_JPG_PLAY: | 2608 | case ZORAN_MAP_MODE_JPG_PLAY: |
2609 | { | 2609 | { |
2610 | struct zoran_sync bs; | 2610 | struct zoran_sync bs; |
2611 | 2611 | ||
2612 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) | 2612 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) |
2613 | buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | 2613 | buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
2614 | else | 2614 | else |
2615 | buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 2615 | buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
2616 | 2616 | ||
2617 | if (buf->type != buf_type) { | 2617 | if (buf->type != buf_type) { |
2618 | dprintk(1, KERN_ERR | 2618 | dprintk(1, KERN_ERR |
2619 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", | 2619 | "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", |
2620 | ZR_DEVNAME(zr), buf->type, fh->map_mode); | 2620 | ZR_DEVNAME(zr), buf->type, fh->map_mode); |
2621 | res = -EINVAL; | 2621 | res = -EINVAL; |
2622 | goto dqbuf_unlock_and_return; | 2622 | goto dqbuf_unlock_and_return; |
2623 | } | 2623 | } |
2624 | 2624 | ||
2625 | num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; | 2625 | num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; |
2626 | 2626 | ||
2627 | if (file->f_flags & O_NONBLOCK && | 2627 | if (file->f_flags & O_NONBLOCK && |
2628 | zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) { | 2628 | zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) { |
2629 | res = -EAGAIN; | 2629 | res = -EAGAIN; |
2630 | goto dqbuf_unlock_and_return; | 2630 | goto dqbuf_unlock_and_return; |
2631 | } | 2631 | } |
2632 | res = jpg_sync(file, &bs); | 2632 | res = jpg_sync(file, &bs); |
2633 | if (res) | 2633 | if (res) |
2634 | goto dqbuf_unlock_and_return; | 2634 | goto dqbuf_unlock_and_return; |
2635 | res = zoran_v4l2_buffer_status(fh, buf, bs.frame); | 2635 | res = zoran_v4l2_buffer_status(fh, buf, bs.frame); |
2636 | break; | 2636 | break; |
2637 | } | 2637 | } |
2638 | 2638 | ||
2639 | default: | 2639 | default: |
2640 | dprintk(1, KERN_ERR | 2640 | dprintk(1, KERN_ERR |
2641 | "%s: VIDIOC_DQBUF - unsupported type %d\n", | 2641 | "%s: VIDIOC_DQBUF - unsupported type %d\n", |
2642 | ZR_DEVNAME(zr), buf->type); | 2642 | ZR_DEVNAME(zr), buf->type); |
2643 | res = -EINVAL; | 2643 | res = -EINVAL; |
2644 | break; | 2644 | break; |
2645 | } | 2645 | } |
2646 | dqbuf_unlock_and_return: | 2646 | dqbuf_unlock_and_return: |
2647 | mutex_unlock(&zr->resource_lock); | 2647 | mutex_unlock(&zr->resource_lock); |
2648 | 2648 | ||
2649 | return res; | 2649 | return res; |
2650 | } | 2650 | } |
2651 | 2651 | ||
2652 | static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) | 2652 | static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) |
2653 | { | 2653 | { |
2654 | struct zoran_fh *fh = __fh; | 2654 | struct zoran_fh *fh = __fh; |
2655 | struct zoran *zr = fh->zr; | 2655 | struct zoran *zr = fh->zr; |
2656 | int res = 0; | 2656 | int res = 0; |
2657 | 2657 | ||
2658 | mutex_lock(&zr->resource_lock); | 2658 | mutex_lock(&zr->resource_lock); |
2659 | 2659 | ||
2660 | switch (fh->map_mode) { | 2660 | switch (fh->map_mode) { |
2661 | case ZORAN_MAP_MODE_RAW: /* raw capture */ | 2661 | case ZORAN_MAP_MODE_RAW: /* raw capture */ |
2662 | if (zr->v4l_buffers.active != ZORAN_ACTIVE || | 2662 | if (zr->v4l_buffers.active != ZORAN_ACTIVE || |
2663 | fh->v4l_buffers.active != ZORAN_ACTIVE) { | 2663 | fh->v4l_buffers.active != ZORAN_ACTIVE) { |
2664 | res = -EBUSY; | 2664 | res = -EBUSY; |
2665 | goto strmon_unlock_and_return; | 2665 | goto strmon_unlock_and_return; |
2666 | } | 2666 | } |
2667 | 2667 | ||
2668 | zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_LOCKED; | 2668 | zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_LOCKED; |
2669 | zr->v4l_settings = fh->v4l_settings; | 2669 | zr->v4l_settings = fh->v4l_settings; |
2670 | 2670 | ||
2671 | zr->v4l_sync_tail = zr->v4l_pend_tail; | 2671 | zr->v4l_sync_tail = zr->v4l_pend_tail; |
2672 | if (!zr->v4l_memgrab_active && | 2672 | if (!zr->v4l_memgrab_active && |
2673 | zr->v4l_pend_head != zr->v4l_pend_tail) { | 2673 | zr->v4l_pend_head != zr->v4l_pend_tail) { |
2674 | zr36057_set_memgrab(zr, 1); | 2674 | zr36057_set_memgrab(zr, 1); |
2675 | } | 2675 | } |
2676 | break; | 2676 | break; |
2677 | 2677 | ||
2678 | case ZORAN_MAP_MODE_JPG_REC: | 2678 | case ZORAN_MAP_MODE_JPG_REC: |
2679 | case ZORAN_MAP_MODE_JPG_PLAY: | 2679 | case ZORAN_MAP_MODE_JPG_PLAY: |
2680 | /* what is the codec mode right now? */ | 2680 | /* what is the codec mode right now? */ |
2681 | if (zr->jpg_buffers.active != ZORAN_ACTIVE || | 2681 | if (zr->jpg_buffers.active != ZORAN_ACTIVE || |
2682 | fh->jpg_buffers.active != ZORAN_ACTIVE) { | 2682 | fh->jpg_buffers.active != ZORAN_ACTIVE) { |
2683 | res = -EBUSY; | 2683 | res = -EBUSY; |
2684 | goto strmon_unlock_and_return; | 2684 | goto strmon_unlock_and_return; |
2685 | } | 2685 | } |
2686 | 2686 | ||
2687 | zr->jpg_buffers.active = fh->jpg_buffers.active = ZORAN_LOCKED; | 2687 | zr->jpg_buffers.active = fh->jpg_buffers.active = ZORAN_LOCKED; |
2688 | 2688 | ||
2689 | if (zr->jpg_que_head != zr->jpg_que_tail) { | 2689 | if (zr->jpg_que_head != zr->jpg_que_tail) { |
2690 | /* Start the jpeg codec when the first frame is queued */ | 2690 | /* Start the jpeg codec when the first frame is queued */ |
2691 | jpeg_start(zr); | 2691 | jpeg_start(zr); |
2692 | } | 2692 | } |
2693 | break; | 2693 | break; |
2694 | 2694 | ||
2695 | default: | 2695 | default: |
2696 | dprintk(1, | 2696 | dprintk(1, |
2697 | KERN_ERR | 2697 | KERN_ERR |
2698 | "%s: VIDIOC_STREAMON - invalid map mode %d\n", | 2698 | "%s: VIDIOC_STREAMON - invalid map mode %d\n", |
2699 | ZR_DEVNAME(zr), fh->map_mode); | 2699 | ZR_DEVNAME(zr), fh->map_mode); |
2700 | res = -EINVAL; | 2700 | res = -EINVAL; |
2701 | break; | 2701 | break; |
2702 | } | 2702 | } |
2703 | strmon_unlock_and_return: | 2703 | strmon_unlock_and_return: |
2704 | mutex_unlock(&zr->resource_lock); | 2704 | mutex_unlock(&zr->resource_lock); |
2705 | 2705 | ||
2706 | return res; | 2706 | return res; |
2707 | } | 2707 | } |
2708 | 2708 | ||
2709 | static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) | 2709 | static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) |
2710 | { | 2710 | { |
2711 | struct zoran_fh *fh = __fh; | 2711 | struct zoran_fh *fh = __fh; |
2712 | struct zoran *zr = fh->zr; | 2712 | struct zoran *zr = fh->zr; |
2713 | int i, res = 0; | 2713 | int i, res = 0; |
2714 | 2714 | ||
2715 | mutex_lock(&zr->resource_lock); | 2715 | mutex_lock(&zr->resource_lock); |
2716 | 2716 | ||
2717 | switch (fh->map_mode) { | 2717 | switch (fh->map_mode) { |
2718 | case ZORAN_MAP_MODE_RAW: /* raw capture */ | 2718 | case ZORAN_MAP_MODE_RAW: /* raw capture */ |
2719 | if (fh->v4l_buffers.active == ZORAN_FREE && | 2719 | if (fh->v4l_buffers.active == ZORAN_FREE && |
2720 | zr->v4l_buffers.active != ZORAN_FREE) { | 2720 | zr->v4l_buffers.active != ZORAN_FREE) { |
2721 | res = -EPERM; /* stay off other's settings! */ | 2721 | res = -EPERM; /* stay off other's settings! */ |
2722 | goto strmoff_unlock_and_return; | 2722 | goto strmoff_unlock_and_return; |
2723 | } | 2723 | } |
2724 | if (zr->v4l_buffers.active == ZORAN_FREE) | 2724 | if (zr->v4l_buffers.active == ZORAN_FREE) |
2725 | goto strmoff_unlock_and_return; | 2725 | goto strmoff_unlock_and_return; |
2726 | 2726 | ||
2727 | /* unload capture */ | 2727 | /* unload capture */ |
2728 | if (zr->v4l_memgrab_active) { | 2728 | if (zr->v4l_memgrab_active) { |
2729 | unsigned long flags; | 2729 | unsigned long flags; |
2730 | 2730 | ||
2731 | spin_lock_irqsave(&zr->spinlock, flags); | 2731 | spin_lock_irqsave(&zr->spinlock, flags); |
2732 | zr36057_set_memgrab(zr, 0); | 2732 | zr36057_set_memgrab(zr, 0); |
2733 | spin_unlock_irqrestore(&zr->spinlock, flags); | 2733 | spin_unlock_irqrestore(&zr->spinlock, flags); |
2734 | } | 2734 | } |
2735 | 2735 | ||
2736 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) | 2736 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) |
2737 | zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; | 2737 | zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; |
2738 | fh->v4l_buffers = zr->v4l_buffers; | 2738 | fh->v4l_buffers = zr->v4l_buffers; |
2739 | 2739 | ||
2740 | zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_FREE; | 2740 | zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_FREE; |
2741 | 2741 | ||
2742 | zr->v4l_grab_seq = 0; | 2742 | zr->v4l_grab_seq = 0; |
2743 | zr->v4l_pend_head = zr->v4l_pend_tail = 0; | 2743 | zr->v4l_pend_head = zr->v4l_pend_tail = 0; |
2744 | zr->v4l_sync_tail = 0; | 2744 | zr->v4l_sync_tail = 0; |
2745 | 2745 | ||
2746 | break; | 2746 | break; |
2747 | 2747 | ||
2748 | case ZORAN_MAP_MODE_JPG_REC: | 2748 | case ZORAN_MAP_MODE_JPG_REC: |
2749 | case ZORAN_MAP_MODE_JPG_PLAY: | 2749 | case ZORAN_MAP_MODE_JPG_PLAY: |
2750 | if (fh->jpg_buffers.active == ZORAN_FREE && | 2750 | if (fh->jpg_buffers.active == ZORAN_FREE && |
2751 | zr->jpg_buffers.active != ZORAN_FREE) { | 2751 | zr->jpg_buffers.active != ZORAN_FREE) { |
2752 | res = -EPERM; /* stay off other's settings! */ | 2752 | res = -EPERM; /* stay off other's settings! */ |
2753 | goto strmoff_unlock_and_return; | 2753 | goto strmoff_unlock_and_return; |
2754 | } | 2754 | } |
2755 | if (zr->jpg_buffers.active == ZORAN_FREE) | 2755 | if (zr->jpg_buffers.active == ZORAN_FREE) |
2756 | goto strmoff_unlock_and_return; | 2756 | goto strmoff_unlock_and_return; |
2757 | 2757 | ||
2758 | res = jpg_qbuf(file, -1, | 2758 | res = jpg_qbuf(file, -1, |
2759 | (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? | 2759 | (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? |
2760 | BUZ_MODE_MOTION_COMPRESS : | 2760 | BUZ_MODE_MOTION_COMPRESS : |
2761 | BUZ_MODE_MOTION_DECOMPRESS); | 2761 | BUZ_MODE_MOTION_DECOMPRESS); |
2762 | if (res) | 2762 | if (res) |
2763 | goto strmoff_unlock_and_return; | 2763 | goto strmoff_unlock_and_return; |
2764 | break; | 2764 | break; |
2765 | default: | 2765 | default: |
2766 | dprintk(1, KERN_ERR | 2766 | dprintk(1, KERN_ERR |
2767 | "%s: VIDIOC_STREAMOFF - invalid map mode %d\n", | 2767 | "%s: VIDIOC_STREAMOFF - invalid map mode %d\n", |
2768 | ZR_DEVNAME(zr), fh->map_mode); | 2768 | ZR_DEVNAME(zr), fh->map_mode); |
2769 | res = -EINVAL; | 2769 | res = -EINVAL; |
2770 | break; | 2770 | break; |
2771 | } | 2771 | } |
2772 | strmoff_unlock_and_return: | 2772 | strmoff_unlock_and_return: |
2773 | mutex_unlock(&zr->resource_lock); | 2773 | mutex_unlock(&zr->resource_lock); |
2774 | 2774 | ||
2775 | return res; | 2775 | return res; |
2776 | } | 2776 | } |
2777 | 2777 | ||
2778 | static int zoran_queryctrl(struct file *file, void *__fh, | 2778 | static int zoran_queryctrl(struct file *file, void *__fh, |
2779 | struct v4l2_queryctrl *ctrl) | 2779 | struct v4l2_queryctrl *ctrl) |
2780 | { | 2780 | { |
2781 | struct zoran_fh *fh = __fh; | 2781 | struct zoran_fh *fh = __fh; |
2782 | struct zoran *zr = fh->zr; | 2782 | struct zoran *zr = fh->zr; |
2783 | 2783 | ||
2784 | /* we only support hue/saturation/contrast/brightness */ | 2784 | /* we only support hue/saturation/contrast/brightness */ |
2785 | if (ctrl->id < V4L2_CID_BRIGHTNESS || | 2785 | if (ctrl->id < V4L2_CID_BRIGHTNESS || |
2786 | ctrl->id > V4L2_CID_HUE) | 2786 | ctrl->id > V4L2_CID_HUE) |
2787 | return -EINVAL; | 2787 | return -EINVAL; |
2788 | 2788 | ||
2789 | decoder_call(zr, core, queryctrl, ctrl); | 2789 | decoder_call(zr, core, queryctrl, ctrl); |
2790 | 2790 | ||
2791 | return 0; | 2791 | return 0; |
2792 | } | 2792 | } |
2793 | 2793 | ||
2794 | static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) | 2794 | static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) |
2795 | { | 2795 | { |
2796 | struct zoran_fh *fh = __fh; | 2796 | struct zoran_fh *fh = __fh; |
2797 | struct zoran *zr = fh->zr; | 2797 | struct zoran *zr = fh->zr; |
2798 | 2798 | ||
2799 | /* we only support hue/saturation/contrast/brightness */ | 2799 | /* we only support hue/saturation/contrast/brightness */ |
2800 | if (ctrl->id < V4L2_CID_BRIGHTNESS || | 2800 | if (ctrl->id < V4L2_CID_BRIGHTNESS || |
2801 | ctrl->id > V4L2_CID_HUE) | 2801 | ctrl->id > V4L2_CID_HUE) |
2802 | return -EINVAL; | 2802 | return -EINVAL; |
2803 | 2803 | ||
2804 | mutex_lock(&zr->resource_lock); | 2804 | mutex_lock(&zr->resource_lock); |
2805 | decoder_call(zr, core, g_ctrl, ctrl); | 2805 | decoder_call(zr, core, g_ctrl, ctrl); |
2806 | mutex_unlock(&zr->resource_lock); | 2806 | mutex_unlock(&zr->resource_lock); |
2807 | 2807 | ||
2808 | return 0; | 2808 | return 0; |
2809 | } | 2809 | } |
2810 | 2810 | ||
2811 | static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) | 2811 | static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) |
2812 | { | 2812 | { |
2813 | struct zoran_fh *fh = __fh; | 2813 | struct zoran_fh *fh = __fh; |
2814 | struct zoran *zr = fh->zr; | 2814 | struct zoran *zr = fh->zr; |
2815 | 2815 | ||
2816 | /* we only support hue/saturation/contrast/brightness */ | 2816 | /* we only support hue/saturation/contrast/brightness */ |
2817 | if (ctrl->id < V4L2_CID_BRIGHTNESS || | 2817 | if (ctrl->id < V4L2_CID_BRIGHTNESS || |
2818 | ctrl->id > V4L2_CID_HUE) | 2818 | ctrl->id > V4L2_CID_HUE) |
2819 | return -EINVAL; | 2819 | return -EINVAL; |
2820 | 2820 | ||
2821 | mutex_lock(&zr->resource_lock); | 2821 | mutex_lock(&zr->resource_lock); |
2822 | decoder_call(zr, core, s_ctrl, ctrl); | 2822 | decoder_call(zr, core, s_ctrl, ctrl); |
2823 | mutex_unlock(&zr->resource_lock); | 2823 | mutex_unlock(&zr->resource_lock); |
2824 | 2824 | ||
2825 | return 0; | 2825 | return 0; |
2826 | } | 2826 | } |
2827 | 2827 | ||
2828 | static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) | 2828 | static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) |
2829 | { | 2829 | { |
2830 | struct zoran_fh *fh = __fh; | 2830 | struct zoran_fh *fh = __fh; |
2831 | struct zoran *zr = fh->zr; | 2831 | struct zoran *zr = fh->zr; |
2832 | 2832 | ||
2833 | mutex_lock(&zr->resource_lock); | 2833 | mutex_lock(&zr->resource_lock); |
2834 | *std = zr->norm; | 2834 | *std = zr->norm; |
2835 | mutex_unlock(&zr->resource_lock); | 2835 | mutex_unlock(&zr->resource_lock); |
2836 | return 0; | 2836 | return 0; |
2837 | } | 2837 | } |
2838 | 2838 | ||
2839 | static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std) | 2839 | static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std) |
2840 | { | 2840 | { |
2841 | struct zoran_fh *fh = __fh; | 2841 | struct zoran_fh *fh = __fh; |
2842 | struct zoran *zr = fh->zr; | 2842 | struct zoran *zr = fh->zr; |
2843 | int res = 0; | 2843 | int res = 0; |
2844 | 2844 | ||
2845 | mutex_lock(&zr->resource_lock); | 2845 | mutex_lock(&zr->resource_lock); |
2846 | res = zoran_set_norm(zr, *std); | 2846 | res = zoran_set_norm(zr, *std); |
2847 | if (res) | 2847 | if (res) |
2848 | goto sstd_unlock_and_return; | 2848 | goto sstd_unlock_and_return; |
2849 | 2849 | ||
2850 | res = wait_grab_pending(zr); | 2850 | res = wait_grab_pending(zr); |
2851 | sstd_unlock_and_return: | 2851 | sstd_unlock_and_return: |
2852 | mutex_unlock(&zr->resource_lock); | 2852 | mutex_unlock(&zr->resource_lock); |
2853 | return res; | 2853 | return res; |
2854 | } | 2854 | } |
2855 | 2855 | ||
2856 | static int zoran_enum_input(struct file *file, void *__fh, | 2856 | static int zoran_enum_input(struct file *file, void *__fh, |
2857 | struct v4l2_input *inp) | 2857 | struct v4l2_input *inp) |
2858 | { | 2858 | { |
2859 | struct zoran_fh *fh = __fh; | 2859 | struct zoran_fh *fh = __fh; |
2860 | struct zoran *zr = fh->zr; | 2860 | struct zoran *zr = fh->zr; |
2861 | 2861 | ||
2862 | if (inp->index < 0 || inp->index >= zr->card.inputs) | 2862 | if (inp->index < 0 || inp->index >= zr->card.inputs) |
2863 | return -EINVAL; | 2863 | return -EINVAL; |
2864 | else { | 2864 | else { |
2865 | int id = inp->index; | 2865 | int id = inp->index; |
2866 | memset(inp, 0, sizeof(*inp)); | 2866 | memset(inp, 0, sizeof(*inp)); |
2867 | inp->index = id; | 2867 | inp->index = id; |
2868 | } | 2868 | } |
2869 | 2869 | ||
2870 | strncpy(inp->name, zr->card.input[inp->index].name, | 2870 | strncpy(inp->name, zr->card.input[inp->index].name, |
2871 | sizeof(inp->name) - 1); | 2871 | sizeof(inp->name) - 1); |
2872 | inp->type = V4L2_INPUT_TYPE_CAMERA; | 2872 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
2873 | inp->std = V4L2_STD_ALL; | 2873 | inp->std = V4L2_STD_ALL; |
2874 | 2874 | ||
2875 | /* Get status of video decoder */ | 2875 | /* Get status of video decoder */ |
2876 | mutex_lock(&zr->resource_lock); | 2876 | mutex_lock(&zr->resource_lock); |
2877 | decoder_call(zr, video, g_input_status, &inp->status); | 2877 | decoder_call(zr, video, g_input_status, &inp->status); |
2878 | mutex_unlock(&zr->resource_lock); | 2878 | mutex_unlock(&zr->resource_lock); |
2879 | return 0; | 2879 | return 0; |
2880 | } | 2880 | } |
2881 | 2881 | ||
2882 | static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) | 2882 | static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) |
2883 | { | 2883 | { |
2884 | struct zoran_fh *fh = __fh; | 2884 | struct zoran_fh *fh = __fh; |
2885 | struct zoran *zr = fh->zr; | 2885 | struct zoran *zr = fh->zr; |
2886 | 2886 | ||
2887 | mutex_lock(&zr->resource_lock); | 2887 | mutex_lock(&zr->resource_lock); |
2888 | *input = zr->input; | 2888 | *input = zr->input; |
2889 | mutex_unlock(&zr->resource_lock); | 2889 | mutex_unlock(&zr->resource_lock); |
2890 | 2890 | ||
2891 | return 0; | 2891 | return 0; |
2892 | } | 2892 | } |
2893 | 2893 | ||
2894 | static int zoran_s_input(struct file *file, void *__fh, unsigned int input) | 2894 | static int zoran_s_input(struct file *file, void *__fh, unsigned int input) |
2895 | { | 2895 | { |
2896 | struct zoran_fh *fh = __fh; | 2896 | struct zoran_fh *fh = __fh; |
2897 | struct zoran *zr = fh->zr; | 2897 | struct zoran *zr = fh->zr; |
2898 | int res; | 2898 | int res; |
2899 | 2899 | ||
2900 | mutex_lock(&zr->resource_lock); | 2900 | mutex_lock(&zr->resource_lock); |
2901 | res = zoran_set_input(zr, input); | 2901 | res = zoran_set_input(zr, input); |
2902 | if (res) | 2902 | if (res) |
2903 | goto sinput_unlock_and_return; | 2903 | goto sinput_unlock_and_return; |
2904 | 2904 | ||
2905 | /* Make sure the changes come into effect */ | 2905 | /* Make sure the changes come into effect */ |
2906 | res = wait_grab_pending(zr); | 2906 | res = wait_grab_pending(zr); |
2907 | sinput_unlock_and_return: | 2907 | sinput_unlock_and_return: |
2908 | mutex_unlock(&zr->resource_lock); | 2908 | mutex_unlock(&zr->resource_lock); |
2909 | return res; | 2909 | return res; |
2910 | } | 2910 | } |
2911 | 2911 | ||
2912 | static int zoran_enum_output(struct file *file, void *__fh, | 2912 | static int zoran_enum_output(struct file *file, void *__fh, |
2913 | struct v4l2_output *outp) | 2913 | struct v4l2_output *outp) |
2914 | { | 2914 | { |
2915 | if (outp->index != 0) | 2915 | if (outp->index != 0) |
2916 | return -EINVAL; | 2916 | return -EINVAL; |
2917 | 2917 | ||
2918 | memset(outp, 0, sizeof(*outp)); | 2918 | memset(outp, 0, sizeof(*outp)); |
2919 | outp->index = 0; | 2919 | outp->index = 0; |
2920 | outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; | 2920 | outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; |
2921 | strncpy(outp->name, "Autodetect", sizeof(outp->name)-1); | 2921 | strncpy(outp->name, "Autodetect", sizeof(outp->name)-1); |
2922 | 2922 | ||
2923 | return 0; | 2923 | return 0; |
2924 | } | 2924 | } |
2925 | 2925 | ||
2926 | static int zoran_g_output(struct file *file, void *__fh, unsigned int *output) | 2926 | static int zoran_g_output(struct file *file, void *__fh, unsigned int *output) |
2927 | { | 2927 | { |
2928 | *output = 0; | 2928 | *output = 0; |
2929 | 2929 | ||
2930 | return 0; | 2930 | return 0; |
2931 | } | 2931 | } |
2932 | 2932 | ||
2933 | static int zoran_s_output(struct file *file, void *__fh, unsigned int output) | 2933 | static int zoran_s_output(struct file *file, void *__fh, unsigned int output) |
2934 | { | 2934 | { |
2935 | if (output != 0) | 2935 | if (output != 0) |
2936 | return -EINVAL; | 2936 | return -EINVAL; |
2937 | 2937 | ||
2938 | return 0; | 2938 | return 0; |
2939 | } | 2939 | } |
2940 | 2940 | ||
2941 | /* cropping (sub-frame capture) */ | 2941 | /* cropping (sub-frame capture) */ |
2942 | static int zoran_cropcap(struct file *file, void *__fh, | 2942 | static int zoran_cropcap(struct file *file, void *__fh, |
2943 | struct v4l2_cropcap *cropcap) | 2943 | struct v4l2_cropcap *cropcap) |
2944 | { | 2944 | { |
2945 | struct zoran_fh *fh = __fh; | 2945 | struct zoran_fh *fh = __fh; |
2946 | struct zoran *zr = fh->zr; | 2946 | struct zoran *zr = fh->zr; |
2947 | int type = cropcap->type, res = 0; | 2947 | int type = cropcap->type, res = 0; |
2948 | 2948 | ||
2949 | memset(cropcap, 0, sizeof(*cropcap)); | 2949 | memset(cropcap, 0, sizeof(*cropcap)); |
2950 | cropcap->type = type; | 2950 | cropcap->type = type; |
2951 | 2951 | ||
2952 | mutex_lock(&zr->resource_lock); | 2952 | mutex_lock(&zr->resource_lock); |
2953 | 2953 | ||
2954 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 2954 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
2955 | (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 2955 | (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
2956 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | 2956 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { |
2957 | dprintk(1, KERN_ERR | 2957 | dprintk(1, KERN_ERR |
2958 | "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n", | 2958 | "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n", |
2959 | ZR_DEVNAME(zr)); | 2959 | ZR_DEVNAME(zr)); |
2960 | res = -EINVAL; | 2960 | res = -EINVAL; |
2961 | goto cropcap_unlock_and_return; | 2961 | goto cropcap_unlock_and_return; |
2962 | } | 2962 | } |
2963 | 2963 | ||
2964 | cropcap->bounds.top = cropcap->bounds.left = 0; | 2964 | cropcap->bounds.top = cropcap->bounds.left = 0; |
2965 | cropcap->bounds.width = BUZ_MAX_WIDTH; | 2965 | cropcap->bounds.width = BUZ_MAX_WIDTH; |
2966 | cropcap->bounds.height = BUZ_MAX_HEIGHT; | 2966 | cropcap->bounds.height = BUZ_MAX_HEIGHT; |
2967 | cropcap->defrect.top = cropcap->defrect.left = 0; | 2967 | cropcap->defrect.top = cropcap->defrect.left = 0; |
2968 | cropcap->defrect.width = BUZ_MIN_WIDTH; | 2968 | cropcap->defrect.width = BUZ_MIN_WIDTH; |
2969 | cropcap->defrect.height = BUZ_MIN_HEIGHT; | 2969 | cropcap->defrect.height = BUZ_MIN_HEIGHT; |
2970 | cropcap_unlock_and_return: | 2970 | cropcap_unlock_and_return: |
2971 | mutex_unlock(&zr->resource_lock); | 2971 | mutex_unlock(&zr->resource_lock); |
2972 | return res; | 2972 | return res; |
2973 | } | 2973 | } |
2974 | 2974 | ||
2975 | static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop) | 2975 | static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop) |
2976 | { | 2976 | { |
2977 | struct zoran_fh *fh = __fh; | 2977 | struct zoran_fh *fh = __fh; |
2978 | struct zoran *zr = fh->zr; | 2978 | struct zoran *zr = fh->zr; |
2979 | int type = crop->type, res = 0; | 2979 | int type = crop->type, res = 0; |
2980 | 2980 | ||
2981 | memset(crop, 0, sizeof(*crop)); | 2981 | memset(crop, 0, sizeof(*crop)); |
2982 | crop->type = type; | 2982 | crop->type = type; |
2983 | 2983 | ||
2984 | mutex_lock(&zr->resource_lock); | 2984 | mutex_lock(&zr->resource_lock); |
2985 | 2985 | ||
2986 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 2986 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
2987 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 2987 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
2988 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | 2988 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { |
2989 | dprintk(1, | 2989 | dprintk(1, |
2990 | KERN_ERR | 2990 | KERN_ERR |
2991 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", | 2991 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", |
2992 | ZR_DEVNAME(zr)); | 2992 | ZR_DEVNAME(zr)); |
2993 | res = -EINVAL; | 2993 | res = -EINVAL; |
2994 | goto gcrop_unlock_and_return; | 2994 | goto gcrop_unlock_and_return; |
2995 | } | 2995 | } |
2996 | 2996 | ||
2997 | crop->c.top = fh->jpg_settings.img_y; | 2997 | crop->c.top = fh->jpg_settings.img_y; |
2998 | crop->c.left = fh->jpg_settings.img_x; | 2998 | crop->c.left = fh->jpg_settings.img_x; |
2999 | crop->c.width = fh->jpg_settings.img_width; | 2999 | crop->c.width = fh->jpg_settings.img_width; |
3000 | crop->c.height = fh->jpg_settings.img_height; | 3000 | crop->c.height = fh->jpg_settings.img_height; |
3001 | 3001 | ||
3002 | gcrop_unlock_and_return: | 3002 | gcrop_unlock_and_return: |
3003 | mutex_unlock(&zr->resource_lock); | 3003 | mutex_unlock(&zr->resource_lock); |
3004 | 3004 | ||
3005 | return res; | 3005 | return res; |
3006 | } | 3006 | } |
3007 | 3007 | ||
3008 | static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop) | 3008 | static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop) |
3009 | { | 3009 | { |
3010 | struct zoran_fh *fh = __fh; | 3010 | struct zoran_fh *fh = __fh; |
3011 | struct zoran *zr = fh->zr; | 3011 | struct zoran *zr = fh->zr; |
3012 | int res = 0; | 3012 | int res = 0; |
3013 | struct zoran_jpg_settings settings; | 3013 | struct zoran_jpg_settings settings; |
3014 | 3014 | ||
3015 | settings = fh->jpg_settings; | 3015 | settings = fh->jpg_settings; |
3016 | 3016 | ||
3017 | mutex_lock(&zr->resource_lock); | 3017 | mutex_lock(&zr->resource_lock); |
3018 | 3018 | ||
3019 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { | 3019 | if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { |
3020 | dprintk(1, KERN_ERR | 3020 | dprintk(1, KERN_ERR |
3021 | "%s: VIDIOC_S_CROP - cannot change settings while active\n", | 3021 | "%s: VIDIOC_S_CROP - cannot change settings while active\n", |
3022 | ZR_DEVNAME(zr)); | 3022 | ZR_DEVNAME(zr)); |
3023 | res = -EBUSY; | 3023 | res = -EBUSY; |
3024 | goto scrop_unlock_and_return; | 3024 | goto scrop_unlock_and_return; |
3025 | } | 3025 | } |
3026 | 3026 | ||
3027 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 3027 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
3028 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 3028 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
3029 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | 3029 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { |
3030 | dprintk(1, KERN_ERR | 3030 | dprintk(1, KERN_ERR |
3031 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", | 3031 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", |
3032 | ZR_DEVNAME(zr)); | 3032 | ZR_DEVNAME(zr)); |
3033 | res = -EINVAL; | 3033 | res = -EINVAL; |
3034 | goto scrop_unlock_and_return; | 3034 | goto scrop_unlock_and_return; |
3035 | } | 3035 | } |
3036 | 3036 | ||
3037 | /* move into a form that we understand */ | 3037 | /* move into a form that we understand */ |
3038 | settings.img_x = crop->c.left; | 3038 | settings.img_x = crop->c.left; |
3039 | settings.img_y = crop->c.top; | 3039 | settings.img_y = crop->c.top; |
3040 | settings.img_width = crop->c.width; | 3040 | settings.img_width = crop->c.width; |
3041 | settings.img_height = crop->c.height; | 3041 | settings.img_height = crop->c.height; |
3042 | 3042 | ||
3043 | /* check validity */ | 3043 | /* check validity */ |
3044 | res = zoran_check_jpg_settings(zr, &settings, 0); | 3044 | res = zoran_check_jpg_settings(zr, &settings, 0); |
3045 | if (res) | 3045 | if (res) |
3046 | goto scrop_unlock_and_return; | 3046 | goto scrop_unlock_and_return; |
3047 | 3047 | ||
3048 | /* accept */ | 3048 | /* accept */ |
3049 | fh->jpg_settings = settings; | 3049 | fh->jpg_settings = settings; |
3050 | 3050 | ||
3051 | scrop_unlock_and_return: | 3051 | scrop_unlock_and_return: |
3052 | mutex_unlock(&zr->resource_lock); | 3052 | mutex_unlock(&zr->resource_lock); |
3053 | return res; | 3053 | return res; |
3054 | } | 3054 | } |
3055 | 3055 | ||
3056 | static int zoran_g_jpegcomp(struct file *file, void *__fh, | 3056 | static int zoran_g_jpegcomp(struct file *file, void *__fh, |
3057 | struct v4l2_jpegcompression *params) | 3057 | struct v4l2_jpegcompression *params) |
3058 | { | 3058 | { |
3059 | struct zoran_fh *fh = __fh; | 3059 | struct zoran_fh *fh = __fh; |
3060 | struct zoran *zr = fh->zr; | 3060 | struct zoran *zr = fh->zr; |
3061 | memset(params, 0, sizeof(*params)); | 3061 | memset(params, 0, sizeof(*params)); |
3062 | 3062 | ||
3063 | mutex_lock(&zr->resource_lock); | 3063 | mutex_lock(&zr->resource_lock); |
3064 | 3064 | ||
3065 | params->quality = fh->jpg_settings.jpg_comp.quality; | 3065 | params->quality = fh->jpg_settings.jpg_comp.quality; |
3066 | params->APPn = fh->jpg_settings.jpg_comp.APPn; | 3066 | params->APPn = fh->jpg_settings.jpg_comp.APPn; |
3067 | memcpy(params->APP_data, | 3067 | memcpy(params->APP_data, |
3068 | fh->jpg_settings.jpg_comp.APP_data, | 3068 | fh->jpg_settings.jpg_comp.APP_data, |
3069 | fh->jpg_settings.jpg_comp.APP_len); | 3069 | fh->jpg_settings.jpg_comp.APP_len); |
3070 | params->APP_len = fh->jpg_settings.jpg_comp.APP_len; | 3070 | params->APP_len = fh->jpg_settings.jpg_comp.APP_len; |
3071 | memcpy(params->COM_data, | 3071 | memcpy(params->COM_data, |
3072 | fh->jpg_settings.jpg_comp.COM_data, | 3072 | fh->jpg_settings.jpg_comp.COM_data, |
3073 | fh->jpg_settings.jpg_comp.COM_len); | 3073 | fh->jpg_settings.jpg_comp.COM_len); |
3074 | params->COM_len = fh->jpg_settings.jpg_comp.COM_len; | 3074 | params->COM_len = fh->jpg_settings.jpg_comp.COM_len; |
3075 | params->jpeg_markers = | 3075 | params->jpeg_markers = |
3076 | fh->jpg_settings.jpg_comp.jpeg_markers; | 3076 | fh->jpg_settings.jpg_comp.jpeg_markers; |
3077 | 3077 | ||
3078 | mutex_unlock(&zr->resource_lock); | 3078 | mutex_unlock(&zr->resource_lock); |
3079 | 3079 | ||
3080 | return 0; | 3080 | return 0; |
3081 | } | 3081 | } |
3082 | 3082 | ||
3083 | static int zoran_s_jpegcomp(struct file *file, void *__fh, | 3083 | static int zoran_s_jpegcomp(struct file *file, void *__fh, |
3084 | struct v4l2_jpegcompression *params) | 3084 | struct v4l2_jpegcompression *params) |
3085 | { | 3085 | { |
3086 | struct zoran_fh *fh = __fh; | 3086 | struct zoran_fh *fh = __fh; |
3087 | struct zoran *zr = fh->zr; | 3087 | struct zoran *zr = fh->zr; |
3088 | int res = 0; | 3088 | int res = 0; |
3089 | struct zoran_jpg_settings settings; | 3089 | struct zoran_jpg_settings settings; |
3090 | 3090 | ||
3091 | settings = fh->jpg_settings; | 3091 | settings = fh->jpg_settings; |
3092 | 3092 | ||
3093 | settings.jpg_comp = *params; | 3093 | settings.jpg_comp = *params; |
3094 | 3094 | ||
3095 | mutex_lock(&zr->resource_lock); | 3095 | mutex_lock(&zr->resource_lock); |
3096 | 3096 | ||
3097 | if (fh->v4l_buffers.active != ZORAN_FREE || | 3097 | if (fh->v4l_buffers.active != ZORAN_FREE || |
3098 | fh->jpg_buffers.active != ZORAN_FREE) { | 3098 | fh->jpg_buffers.active != ZORAN_FREE) { |
3099 | dprintk(1, KERN_WARNING | 3099 | dprintk(1, KERN_WARNING |
3100 | "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n", | 3100 | "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n", |
3101 | ZR_DEVNAME(zr)); | 3101 | ZR_DEVNAME(zr)); |
3102 | res = -EBUSY; | 3102 | res = -EBUSY; |
3103 | goto sjpegc_unlock_and_return; | 3103 | goto sjpegc_unlock_and_return; |
3104 | } | 3104 | } |
3105 | 3105 | ||
3106 | res = zoran_check_jpg_settings(zr, &settings, 0); | 3106 | res = zoran_check_jpg_settings(zr, &settings, 0); |
3107 | if (res) | 3107 | if (res) |
3108 | goto sjpegc_unlock_and_return; | 3108 | goto sjpegc_unlock_and_return; |
3109 | if (!fh->jpg_buffers.allocated) | 3109 | if (!fh->jpg_buffers.allocated) |
3110 | fh->jpg_buffers.buffer_size = | 3110 | fh->jpg_buffers.buffer_size = |
3111 | zoran_v4l2_calc_bufsize(&fh->jpg_settings); | 3111 | zoran_v4l2_calc_bufsize(&fh->jpg_settings); |
3112 | fh->jpg_settings.jpg_comp = *params = settings.jpg_comp; | 3112 | fh->jpg_settings.jpg_comp = *params = settings.jpg_comp; |
3113 | sjpegc_unlock_and_return: | 3113 | sjpegc_unlock_and_return: |
3114 | mutex_unlock(&zr->resource_lock); | 3114 | mutex_unlock(&zr->resource_lock); |
3115 | 3115 | ||
3116 | return res; | 3116 | return res; |
3117 | } | 3117 | } |
3118 | 3118 | ||
3119 | static unsigned int | 3119 | static unsigned int |
3120 | zoran_poll (struct file *file, | 3120 | zoran_poll (struct file *file, |
3121 | poll_table *wait) | 3121 | poll_table *wait) |
3122 | { | 3122 | { |
3123 | struct zoran_fh *fh = file->private_data; | 3123 | struct zoran_fh *fh = file->private_data; |
3124 | struct zoran *zr = fh->zr; | 3124 | struct zoran *zr = fh->zr; |
3125 | int res = 0, frame; | 3125 | int res = 0, frame; |
3126 | unsigned long flags; | 3126 | unsigned long flags; |
3127 | 3127 | ||
3128 | /* we should check whether buffers are ready to be synced on | 3128 | /* we should check whether buffers are ready to be synced on |
3129 | * (w/o waits - O_NONBLOCK) here | 3129 | * (w/o waits - O_NONBLOCK) here |
3130 | * if ready for read (sync), return POLLIN|POLLRDNORM, | 3130 | * if ready for read (sync), return POLLIN|POLLRDNORM, |
3131 | * if ready for write (sync), return POLLOUT|POLLWRNORM, | 3131 | * if ready for write (sync), return POLLOUT|POLLWRNORM, |
3132 | * if error, return POLLERR, | 3132 | * if error, return POLLERR, |
3133 | * if no buffers queued or so, return POLLNVAL | 3133 | * if no buffers queued or so, return POLLNVAL |
3134 | */ | 3134 | */ |
3135 | 3135 | ||
3136 | mutex_lock(&zr->resource_lock); | 3136 | mutex_lock(&zr->resource_lock); |
3137 | 3137 | ||
3138 | switch (fh->map_mode) { | 3138 | switch (fh->map_mode) { |
3139 | case ZORAN_MAP_MODE_RAW: | 3139 | case ZORAN_MAP_MODE_RAW: |
3140 | poll_wait(file, &zr->v4l_capq, wait); | 3140 | poll_wait(file, &zr->v4l_capq, wait); |
3141 | frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; | 3141 | frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; |
3142 | 3142 | ||
3143 | spin_lock_irqsave(&zr->spinlock, flags); | 3143 | spin_lock_irqsave(&zr->spinlock, flags); |
3144 | dprintk(3, | 3144 | dprintk(3, |
3145 | KERN_DEBUG | 3145 | KERN_DEBUG |
3146 | "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n", | 3146 | "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n", |
3147 | ZR_DEVNAME(zr), __func__, | 3147 | ZR_DEVNAME(zr), __func__, |
3148 | "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail, | 3148 | "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail, |
3149 | "UPMD"[zr->v4l_buffers.buffer[frame].state], | 3149 | "UPMD"[zr->v4l_buffers.buffer[frame].state], |
3150 | zr->v4l_pend_tail, zr->v4l_pend_head); | 3150 | zr->v4l_pend_tail, zr->v4l_pend_head); |
3151 | /* Process is the one capturing? */ | 3151 | /* Process is the one capturing? */ |
3152 | if (fh->v4l_buffers.active != ZORAN_FREE && | 3152 | if (fh->v4l_buffers.active != ZORAN_FREE && |
3153 | /* Buffer ready to DQBUF? */ | 3153 | /* Buffer ready to DQBUF? */ |
3154 | zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE) | 3154 | zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE) |
3155 | res = POLLIN | POLLRDNORM; | 3155 | res = POLLIN | POLLRDNORM; |
3156 | spin_unlock_irqrestore(&zr->spinlock, flags); | 3156 | spin_unlock_irqrestore(&zr->spinlock, flags); |
3157 | 3157 | ||
3158 | break; | 3158 | break; |
3159 | 3159 | ||
3160 | case ZORAN_MAP_MODE_JPG_REC: | 3160 | case ZORAN_MAP_MODE_JPG_REC: |
3161 | case ZORAN_MAP_MODE_JPG_PLAY: | 3161 | case ZORAN_MAP_MODE_JPG_PLAY: |
3162 | poll_wait(file, &zr->jpg_capq, wait); | 3162 | poll_wait(file, &zr->jpg_capq, wait); |
3163 | frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; | 3163 | frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; |
3164 | 3164 | ||
3165 | spin_lock_irqsave(&zr->spinlock, flags); | 3165 | spin_lock_irqsave(&zr->spinlock, flags); |
3166 | dprintk(3, | 3166 | dprintk(3, |
3167 | KERN_DEBUG | 3167 | KERN_DEBUG |
3168 | "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n", | 3168 | "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n", |
3169 | ZR_DEVNAME(zr), __func__, | 3169 | ZR_DEVNAME(zr), __func__, |
3170 | "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail, | 3170 | "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail, |
3171 | "UPMD"[zr->jpg_buffers.buffer[frame].state], | 3171 | "UPMD"[zr->jpg_buffers.buffer[frame].state], |
3172 | zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head); | 3172 | zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head); |
3173 | if (fh->jpg_buffers.active != ZORAN_FREE && | 3173 | if (fh->jpg_buffers.active != ZORAN_FREE && |
3174 | zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) { | 3174 | zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) { |
3175 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) | 3175 | if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) |
3176 | res = POLLIN | POLLRDNORM; | 3176 | res = POLLIN | POLLRDNORM; |
3177 | else | 3177 | else |
3178 | res = POLLOUT | POLLWRNORM; | 3178 | res = POLLOUT | POLLWRNORM; |
3179 | } | 3179 | } |
3180 | spin_unlock_irqrestore(&zr->spinlock, flags); | 3180 | spin_unlock_irqrestore(&zr->spinlock, flags); |
3181 | 3181 | ||
3182 | break; | 3182 | break; |
3183 | 3183 | ||
3184 | default: | 3184 | default: |
3185 | dprintk(1, | 3185 | dprintk(1, |
3186 | KERN_ERR | 3186 | KERN_ERR |
3187 | "%s: zoran_poll() - internal error, unknown map_mode=%d\n", | 3187 | "%s: zoran_poll() - internal error, unknown map_mode=%d\n", |
3188 | ZR_DEVNAME(zr), fh->map_mode); | 3188 | ZR_DEVNAME(zr), fh->map_mode); |
3189 | res = POLLNVAL; | 3189 | res = POLLNVAL; |
3190 | } | 3190 | } |
3191 | 3191 | ||
3192 | mutex_unlock(&zr->resource_lock); | 3192 | mutex_unlock(&zr->resource_lock); |
3193 | 3193 | ||
3194 | return res; | 3194 | return res; |
3195 | } | 3195 | } |
3196 | 3196 | ||
3197 | 3197 | ||
3198 | /* | 3198 | /* |
3199 | * This maps the buffers to user space. | 3199 | * This maps the buffers to user space. |
3200 | * | 3200 | * |
3201 | * Depending on the state of fh->map_mode | 3201 | * Depending on the state of fh->map_mode |
3202 | * the V4L or the MJPEG buffers are mapped | 3202 | * the V4L or the MJPEG buffers are mapped |
3203 | * per buffer or all together | 3203 | * per buffer or all together |
3204 | * | 3204 | * |
3205 | * Note that we need to connect to some | 3205 | * Note that we need to connect to some |
3206 | * unmap signal event to unmap the de-allocate | 3206 | * unmap signal event to unmap the de-allocate |
3207 | * the buffer accordingly (zoran_vm_close()) | 3207 | * the buffer accordingly (zoran_vm_close()) |
3208 | */ | 3208 | */ |
3209 | 3209 | ||
3210 | static void | 3210 | static void |
3211 | zoran_vm_open (struct vm_area_struct *vma) | 3211 | zoran_vm_open (struct vm_area_struct *vma) |
3212 | { | 3212 | { |
3213 | struct zoran_mapping *map = vma->vm_private_data; | 3213 | struct zoran_mapping *map = vma->vm_private_data; |
3214 | 3214 | ||
3215 | map->count++; | 3215 | map->count++; |
3216 | } | 3216 | } |
3217 | 3217 | ||
3218 | static void | 3218 | static void |
3219 | zoran_vm_close (struct vm_area_struct *vma) | 3219 | zoran_vm_close (struct vm_area_struct *vma) |
3220 | { | 3220 | { |
3221 | struct zoran_mapping *map = vma->vm_private_data; | 3221 | struct zoran_mapping *map = vma->vm_private_data; |
3222 | struct file *file = map->file; | 3222 | struct file *file = map->file; |
3223 | struct zoran_fh *fh = file->private_data; | 3223 | struct zoran_fh *fh = file->private_data; |
3224 | struct zoran *zr = fh->zr; | 3224 | struct zoran *zr = fh->zr; |
3225 | int i; | 3225 | int i; |
3226 | 3226 | ||
3227 | map->count--; | 3227 | map->count--; |
3228 | if (map->count == 0) { | 3228 | if (map->count == 0) { |
3229 | switch (fh->map_mode) { | 3229 | switch (fh->map_mode) { |
3230 | case ZORAN_MAP_MODE_JPG_REC: | 3230 | case ZORAN_MAP_MODE_JPG_REC: |
3231 | case ZORAN_MAP_MODE_JPG_PLAY: | 3231 | case ZORAN_MAP_MODE_JPG_PLAY: |
3232 | 3232 | ||
3233 | dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n", | 3233 | dprintk(3, KERN_INFO "%s: munmap(MJPEG)\n", |
3234 | ZR_DEVNAME(zr)); | 3234 | ZR_DEVNAME(zr)); |
3235 | 3235 | ||
3236 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { | 3236 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { |
3237 | if (fh->jpg_buffers.buffer[i].map == map) { | 3237 | if (fh->jpg_buffers.buffer[i].map == map) { |
3238 | fh->jpg_buffers.buffer[i].map = | 3238 | fh->jpg_buffers.buffer[i].map = |
3239 | NULL; | 3239 | NULL; |
3240 | } | 3240 | } |
3241 | } | 3241 | } |
3242 | kfree(map); | 3242 | kfree(map); |
3243 | 3243 | ||
3244 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) | 3244 | for (i = 0; i < fh->jpg_buffers.num_buffers; i++) |
3245 | if (fh->jpg_buffers.buffer[i].map) | 3245 | if (fh->jpg_buffers.buffer[i].map) |
3246 | break; | 3246 | break; |
3247 | if (i == fh->jpg_buffers.num_buffers) { | 3247 | if (i == fh->jpg_buffers.num_buffers) { |
3248 | mutex_lock(&zr->resource_lock); | 3248 | mutex_lock(&zr->resource_lock); |
3249 | 3249 | ||
3250 | if (fh->jpg_buffers.active != ZORAN_FREE) { | 3250 | if (fh->jpg_buffers.active != ZORAN_FREE) { |
3251 | jpg_qbuf(file, -1, zr->codec_mode); | 3251 | jpg_qbuf(file, -1, zr->codec_mode); |
3252 | zr->jpg_buffers.allocated = 0; | 3252 | zr->jpg_buffers.allocated = 0; |
3253 | zr->jpg_buffers.active = | 3253 | zr->jpg_buffers.active = |
3254 | fh->jpg_buffers.active = | 3254 | fh->jpg_buffers.active = |
3255 | ZORAN_FREE; | 3255 | ZORAN_FREE; |
3256 | } | 3256 | } |
3257 | jpg_fbuffer_free(file); | 3257 | jpg_fbuffer_free(file); |
3258 | mutex_unlock(&zr->resource_lock); | 3258 | mutex_unlock(&zr->resource_lock); |
3259 | } | 3259 | } |
3260 | 3260 | ||
3261 | break; | 3261 | break; |
3262 | 3262 | ||
3263 | case ZORAN_MAP_MODE_RAW: | 3263 | case ZORAN_MAP_MODE_RAW: |
3264 | 3264 | ||
3265 | dprintk(3, KERN_INFO "%s: munmap(V4L)\n", | 3265 | dprintk(3, KERN_INFO "%s: munmap(V4L)\n", |
3266 | ZR_DEVNAME(zr)); | 3266 | ZR_DEVNAME(zr)); |
3267 | 3267 | ||
3268 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { | 3268 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { |
3269 | if (fh->v4l_buffers.buffer[i].map == map) { | 3269 | if (fh->v4l_buffers.buffer[i].map == map) { |
3270 | /* unqueue/unmap */ | 3270 | /* unqueue/unmap */ |
3271 | fh->v4l_buffers.buffer[i].map = | 3271 | fh->v4l_buffers.buffer[i].map = |
3272 | NULL; | 3272 | NULL; |
3273 | } | 3273 | } |
3274 | } | 3274 | } |
3275 | kfree(map); | 3275 | kfree(map); |
3276 | 3276 | ||
3277 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) | 3277 | for (i = 0; i < fh->v4l_buffers.num_buffers; i++) |
3278 | if (fh->v4l_buffers.buffer[i].map) | 3278 | if (fh->v4l_buffers.buffer[i].map) |
3279 | break; | 3279 | break; |
3280 | if (i == fh->v4l_buffers.num_buffers) { | 3280 | if (i == fh->v4l_buffers.num_buffers) { |
3281 | mutex_lock(&zr->resource_lock); | 3281 | mutex_lock(&zr->resource_lock); |
3282 | 3282 | ||
3283 | if (fh->v4l_buffers.active != ZORAN_FREE) { | 3283 | if (fh->v4l_buffers.active != ZORAN_FREE) { |
3284 | unsigned long flags; | 3284 | unsigned long flags; |
3285 | 3285 | ||
3286 | spin_lock_irqsave(&zr->spinlock, flags); | 3286 | spin_lock_irqsave(&zr->spinlock, flags); |
3287 | zr36057_set_memgrab(zr, 0); | 3287 | zr36057_set_memgrab(zr, 0); |
3288 | zr->v4l_buffers.allocated = 0; | 3288 | zr->v4l_buffers.allocated = 0; |
3289 | zr->v4l_buffers.active = | 3289 | zr->v4l_buffers.active = |
3290 | fh->v4l_buffers.active = | 3290 | fh->v4l_buffers.active = |
3291 | ZORAN_FREE; | 3291 | ZORAN_FREE; |
3292 | spin_unlock_irqrestore(&zr->spinlock, flags); | 3292 | spin_unlock_irqrestore(&zr->spinlock, flags); |
3293 | } | 3293 | } |
3294 | v4l_fbuffer_free(file); | 3294 | v4l_fbuffer_free(file); |
3295 | mutex_unlock(&zr->resource_lock); | 3295 | mutex_unlock(&zr->resource_lock); |
3296 | } | 3296 | } |
3297 | 3297 | ||
3298 | break; | 3298 | break; |
3299 | 3299 | ||
3300 | default: | 3300 | default: |
3301 | printk(KERN_ERR | 3301 | printk(KERN_ERR |
3302 | "%s: munmap() - internal error - unknown map mode %d\n", | 3302 | "%s: munmap() - internal error - unknown map mode %d\n", |
3303 | ZR_DEVNAME(zr), fh->map_mode); | 3303 | ZR_DEVNAME(zr), fh->map_mode); |
3304 | break; | 3304 | break; |
3305 | 3305 | ||
3306 | } | 3306 | } |
3307 | } | 3307 | } |
3308 | } | 3308 | } |
3309 | 3309 | ||
3310 | static struct vm_operations_struct zoran_vm_ops = { | 3310 | static struct vm_operations_struct zoran_vm_ops = { |
3311 | .open = zoran_vm_open, | 3311 | .open = zoran_vm_open, |
3312 | .close = zoran_vm_close, | 3312 | .close = zoran_vm_close, |
3313 | }; | 3313 | }; |
3314 | 3314 | ||
3315 | static int | 3315 | static int |
3316 | zoran_mmap (struct file *file, | 3316 | zoran_mmap (struct file *file, |
3317 | struct vm_area_struct *vma) | 3317 | struct vm_area_struct *vma) |
3318 | { | 3318 | { |
3319 | struct zoran_fh *fh = file->private_data; | 3319 | struct zoran_fh *fh = file->private_data; |
3320 | struct zoran *zr = fh->zr; | 3320 | struct zoran *zr = fh->zr; |
3321 | unsigned long size = (vma->vm_end - vma->vm_start); | 3321 | unsigned long size = (vma->vm_end - vma->vm_start); |
3322 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 3322 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; |
3323 | int i, j; | 3323 | int i, j; |
3324 | unsigned long page, start = vma->vm_start, todo, pos, fraglen; | 3324 | unsigned long page, start = vma->vm_start, todo, pos, fraglen; |
3325 | int first, last; | 3325 | int first, last; |
3326 | struct zoran_mapping *map; | 3326 | struct zoran_mapping *map; |
3327 | int res = 0; | 3327 | int res = 0; |
3328 | 3328 | ||
3329 | dprintk(3, | 3329 | dprintk(3, |
3330 | KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n", | 3330 | KERN_INFO "%s: mmap(%s) of 0x%08lx-0x%08lx (size=%lu)\n", |
3331 | ZR_DEVNAME(zr), | 3331 | ZR_DEVNAME(zr), |
3332 | fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG", | 3332 | fh->map_mode == ZORAN_MAP_MODE_RAW ? "V4L" : "MJPEG", |
3333 | vma->vm_start, vma->vm_end, size); | 3333 | vma->vm_start, vma->vm_end, size); |
3334 | 3334 | ||
3335 | if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) || | 3335 | if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) || |
3336 | !(vma->vm_flags & VM_WRITE)) { | 3336 | !(vma->vm_flags & VM_WRITE)) { |
3337 | dprintk(1, | 3337 | dprintk(1, |
3338 | KERN_ERR | 3338 | KERN_ERR |
3339 | "%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n", | 3339 | "%s: mmap() - no MAP_SHARED/PROT_{READ,WRITE} given\n", |
3340 | ZR_DEVNAME(zr)); | 3340 | ZR_DEVNAME(zr)); |
3341 | return -EINVAL; | 3341 | return -EINVAL; |
3342 | } | 3342 | } |
3343 | 3343 | ||
3344 | switch (fh->map_mode) { | 3344 | switch (fh->map_mode) { |
3345 | 3345 | ||
3346 | case ZORAN_MAP_MODE_JPG_REC: | 3346 | case ZORAN_MAP_MODE_JPG_REC: |
3347 | case ZORAN_MAP_MODE_JPG_PLAY: | 3347 | case ZORAN_MAP_MODE_JPG_PLAY: |
3348 | 3348 | ||
3349 | /* lock */ | 3349 | /* lock */ |
3350 | mutex_lock(&zr->resource_lock); | 3350 | mutex_lock(&zr->resource_lock); |
3351 | 3351 | ||
3352 | /* Map the MJPEG buffers */ | 3352 | /* Map the MJPEG buffers */ |
3353 | if (!fh->jpg_buffers.allocated) { | 3353 | if (!fh->jpg_buffers.allocated) { |
3354 | dprintk(1, | 3354 | dprintk(1, |
3355 | KERN_ERR | 3355 | KERN_ERR |
3356 | "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n", | 3356 | "%s: zoran_mmap(MJPEG) - buffers not yet allocated\n", |
3357 | ZR_DEVNAME(zr)); | 3357 | ZR_DEVNAME(zr)); |
3358 | res = -ENOMEM; | 3358 | res = -ENOMEM; |
3359 | goto jpg_mmap_unlock_and_return; | 3359 | goto jpg_mmap_unlock_and_return; |
3360 | } | 3360 | } |
3361 | 3361 | ||
3362 | first = offset / fh->jpg_buffers.buffer_size; | 3362 | first = offset / fh->jpg_buffers.buffer_size; |
3363 | last = first - 1 + size / fh->jpg_buffers.buffer_size; | 3363 | last = first - 1 + size / fh->jpg_buffers.buffer_size; |
3364 | if (offset % fh->jpg_buffers.buffer_size != 0 || | 3364 | if (offset % fh->jpg_buffers.buffer_size != 0 || |
3365 | size % fh->jpg_buffers.buffer_size != 0 || first < 0 || | 3365 | size % fh->jpg_buffers.buffer_size != 0 || first < 0 || |
3366 | last < 0 || first >= fh->jpg_buffers.num_buffers || | 3366 | last < 0 || first >= fh->jpg_buffers.num_buffers || |
3367 | last >= fh->jpg_buffers.num_buffers) { | 3367 | last >= fh->jpg_buffers.num_buffers) { |
3368 | dprintk(1, | 3368 | dprintk(1, |
3369 | KERN_ERR | 3369 | KERN_ERR |
3370 | "%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", | 3370 | "%s: mmap(MJPEG) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", |
3371 | ZR_DEVNAME(zr), offset, size, | 3371 | ZR_DEVNAME(zr), offset, size, |
3372 | fh->jpg_buffers.buffer_size, | 3372 | fh->jpg_buffers.buffer_size, |
3373 | fh->jpg_buffers.num_buffers); | 3373 | fh->jpg_buffers.num_buffers); |
3374 | res = -EINVAL; | 3374 | res = -EINVAL; |
3375 | goto jpg_mmap_unlock_and_return; | 3375 | goto jpg_mmap_unlock_and_return; |
3376 | } | 3376 | } |
3377 | for (i = first; i <= last; i++) { | 3377 | for (i = first; i <= last; i++) { |
3378 | if (fh->jpg_buffers.buffer[i].map) { | 3378 | if (fh->jpg_buffers.buffer[i].map) { |
3379 | dprintk(1, | 3379 | dprintk(1, |
3380 | KERN_ERR | 3380 | KERN_ERR |
3381 | "%s: mmap(MJPEG) - buffer %d already mapped\n", | 3381 | "%s: mmap(MJPEG) - buffer %d already mapped\n", |
3382 | ZR_DEVNAME(zr), i); | 3382 | ZR_DEVNAME(zr), i); |
3383 | res = -EBUSY; | 3383 | res = -EBUSY; |
3384 | goto jpg_mmap_unlock_and_return; | 3384 | goto jpg_mmap_unlock_and_return; |
3385 | } | 3385 | } |
3386 | } | 3386 | } |
3387 | 3387 | ||
3388 | /* map these buffers (v4l_buffers[i]) */ | 3388 | /* map these buffers (v4l_buffers[i]) */ |
3389 | map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); | 3389 | map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); |
3390 | if (!map) { | 3390 | if (!map) { |
3391 | res = -ENOMEM; | 3391 | res = -ENOMEM; |
3392 | goto jpg_mmap_unlock_and_return; | 3392 | goto jpg_mmap_unlock_and_return; |
3393 | } | 3393 | } |
3394 | map->file = file; | 3394 | map->file = file; |
3395 | map->count = 1; | 3395 | map->count = 1; |
3396 | 3396 | ||
3397 | vma->vm_ops = &zoran_vm_ops; | 3397 | vma->vm_ops = &zoran_vm_ops; |
3398 | vma->vm_flags |= VM_DONTEXPAND; | 3398 | vma->vm_flags |= VM_DONTEXPAND; |
3399 | vma->vm_private_data = map; | 3399 | vma->vm_private_data = map; |
3400 | 3400 | ||
3401 | for (i = first; i <= last; i++) { | 3401 | for (i = first; i <= last; i++) { |
3402 | for (j = 0; | 3402 | for (j = 0; |
3403 | j < fh->jpg_buffers.buffer_size / PAGE_SIZE; | 3403 | j < fh->jpg_buffers.buffer_size / PAGE_SIZE; |
3404 | j++) { | 3404 | j++) { |
3405 | fraglen = | 3405 | fraglen = |
3406 | (le32_to_cpu(fh->jpg_buffers.buffer[i]. | 3406 | (le32_to_cpu(fh->jpg_buffers.buffer[i]. |
3407 | frag_tab[2 * j + 1]) & ~1) << 1; | 3407 | frag_tab[2 * j + 1]) & ~1) << 1; |
3408 | todo = size; | 3408 | todo = size; |
3409 | if (todo > fraglen) | 3409 | if (todo > fraglen) |
3410 | todo = fraglen; | 3410 | todo = fraglen; |
3411 | pos = | 3411 | pos = |
3412 | le32_to_cpu(fh->jpg_buffers. | 3412 | le32_to_cpu(fh->jpg_buffers. |
3413 | buffer[i].frag_tab[2 * j]); | 3413 | buffer[i].frag_tab[2 * j]); |
3414 | /* should just be pos on i386 */ | 3414 | /* should just be pos on i386 */ |
3415 | page = virt_to_phys(bus_to_virt(pos)) | 3415 | page = virt_to_phys(bus_to_virt(pos)) |
3416 | >> PAGE_SHIFT; | 3416 | >> PAGE_SHIFT; |
3417 | if (remap_pfn_range(vma, start, page, | 3417 | if (remap_pfn_range(vma, start, page, |
3418 | todo, PAGE_SHARED)) { | 3418 | todo, PAGE_SHARED)) { |
3419 | dprintk(1, | 3419 | dprintk(1, |
3420 | KERN_ERR | 3420 | KERN_ERR |
3421 | "%s: zoran_mmap(V4L) - remap_pfn_range failed\n", | 3421 | "%s: zoran_mmap(V4L) - remap_pfn_range failed\n", |
3422 | ZR_DEVNAME(zr)); | 3422 | ZR_DEVNAME(zr)); |
3423 | res = -EAGAIN; | 3423 | res = -EAGAIN; |
3424 | goto jpg_mmap_unlock_and_return; | 3424 | goto jpg_mmap_unlock_and_return; |
3425 | } | 3425 | } |
3426 | size -= todo; | 3426 | size -= todo; |
3427 | start += todo; | 3427 | start += todo; |
3428 | if (size == 0) | 3428 | if (size == 0) |
3429 | break; | 3429 | break; |
3430 | if (le32_to_cpu(fh->jpg_buffers.buffer[i]. | 3430 | if (le32_to_cpu(fh->jpg_buffers.buffer[i]. |
3431 | frag_tab[2 * j + 1]) & 1) | 3431 | frag_tab[2 * j + 1]) & 1) |
3432 | break; /* was last fragment */ | 3432 | break; /* was last fragment */ |
3433 | } | 3433 | } |
3434 | fh->jpg_buffers.buffer[i].map = map; | 3434 | fh->jpg_buffers.buffer[i].map = map; |
3435 | if (size == 0) | 3435 | if (size == 0) |
3436 | break; | 3436 | break; |
3437 | 3437 | ||
3438 | } | 3438 | } |
3439 | jpg_mmap_unlock_and_return: | 3439 | jpg_mmap_unlock_and_return: |
3440 | mutex_unlock(&zr->resource_lock); | 3440 | mutex_unlock(&zr->resource_lock); |
3441 | 3441 | ||
3442 | break; | 3442 | break; |
3443 | 3443 | ||
3444 | case ZORAN_MAP_MODE_RAW: | 3444 | case ZORAN_MAP_MODE_RAW: |
3445 | 3445 | ||
3446 | mutex_lock(&zr->resource_lock); | 3446 | mutex_lock(&zr->resource_lock); |
3447 | 3447 | ||
3448 | /* Map the V4L buffers */ | 3448 | /* Map the V4L buffers */ |
3449 | if (!fh->v4l_buffers.allocated) { | 3449 | if (!fh->v4l_buffers.allocated) { |
3450 | dprintk(1, | 3450 | dprintk(1, |
3451 | KERN_ERR | 3451 | KERN_ERR |
3452 | "%s: zoran_mmap(V4L) - buffers not yet allocated\n", | 3452 | "%s: zoran_mmap(V4L) - buffers not yet allocated\n", |
3453 | ZR_DEVNAME(zr)); | 3453 | ZR_DEVNAME(zr)); |
3454 | res = -ENOMEM; | 3454 | res = -ENOMEM; |
3455 | goto v4l_mmap_unlock_and_return; | 3455 | goto v4l_mmap_unlock_and_return; |
3456 | } | 3456 | } |
3457 | 3457 | ||
3458 | first = offset / fh->v4l_buffers.buffer_size; | 3458 | first = offset / fh->v4l_buffers.buffer_size; |
3459 | last = first - 1 + size / fh->v4l_buffers.buffer_size; | 3459 | last = first - 1 + size / fh->v4l_buffers.buffer_size; |
3460 | if (offset % fh->v4l_buffers.buffer_size != 0 || | 3460 | if (offset % fh->v4l_buffers.buffer_size != 0 || |
3461 | size % fh->v4l_buffers.buffer_size != 0 || first < 0 || | 3461 | size % fh->v4l_buffers.buffer_size != 0 || first < 0 || |
3462 | last < 0 || first >= fh->v4l_buffers.num_buffers || | 3462 | last < 0 || first >= fh->v4l_buffers.num_buffers || |
3463 | last >= fh->v4l_buffers.buffer_size) { | 3463 | last >= fh->v4l_buffers.buffer_size) { |
3464 | dprintk(1, | 3464 | dprintk(1, |
3465 | KERN_ERR | 3465 | KERN_ERR |
3466 | "%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", | 3466 | "%s: mmap(V4L) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", |
3467 | ZR_DEVNAME(zr), offset, size, | 3467 | ZR_DEVNAME(zr), offset, size, |
3468 | fh->v4l_buffers.buffer_size, | 3468 | fh->v4l_buffers.buffer_size, |
3469 | fh->v4l_buffers.num_buffers); | 3469 | fh->v4l_buffers.num_buffers); |
3470 | res = -EINVAL; | 3470 | res = -EINVAL; |
3471 | goto v4l_mmap_unlock_and_return; | 3471 | goto v4l_mmap_unlock_and_return; |
3472 | } | 3472 | } |
3473 | for (i = first; i <= last; i++) { | 3473 | for (i = first; i <= last; i++) { |
3474 | if (fh->v4l_buffers.buffer[i].map) { | 3474 | if (fh->v4l_buffers.buffer[i].map) { |
3475 | dprintk(1, | 3475 | dprintk(1, |
3476 | KERN_ERR | 3476 | KERN_ERR |
3477 | "%s: mmap(V4L) - buffer %d already mapped\n", | 3477 | "%s: mmap(V4L) - buffer %d already mapped\n", |
3478 | ZR_DEVNAME(zr), i); | 3478 | ZR_DEVNAME(zr), i); |
3479 | res = -EBUSY; | 3479 | res = -EBUSY; |
3480 | goto v4l_mmap_unlock_and_return; | 3480 | goto v4l_mmap_unlock_and_return; |
3481 | } | 3481 | } |
3482 | } | 3482 | } |
3483 | 3483 | ||
3484 | /* map these buffers (v4l_buffers[i]) */ | 3484 | /* map these buffers (v4l_buffers[i]) */ |
3485 | map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); | 3485 | map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); |
3486 | if (!map) { | 3486 | if (!map) { |
3487 | res = -ENOMEM; | 3487 | res = -ENOMEM; |
3488 | goto v4l_mmap_unlock_and_return; | 3488 | goto v4l_mmap_unlock_and_return; |
3489 | } | 3489 | } |
3490 | map->file = file; | 3490 | map->file = file; |
3491 | map->count = 1; | 3491 | map->count = 1; |
3492 | 3492 | ||
3493 | vma->vm_ops = &zoran_vm_ops; | 3493 | vma->vm_ops = &zoran_vm_ops; |
3494 | vma->vm_flags |= VM_DONTEXPAND; | 3494 | vma->vm_flags |= VM_DONTEXPAND; |
3495 | vma->vm_private_data = map; | 3495 | vma->vm_private_data = map; |
3496 | 3496 | ||
3497 | for (i = first; i <= last; i++) { | 3497 | for (i = first; i <= last; i++) { |
3498 | todo = size; | 3498 | todo = size; |
3499 | if (todo > fh->v4l_buffers.buffer_size) | 3499 | if (todo > fh->v4l_buffers.buffer_size) |
3500 | todo = fh->v4l_buffers.buffer_size; | 3500 | todo = fh->v4l_buffers.buffer_size; |
3501 | page = fh->v4l_buffers.buffer[i].fbuffer_phys; | 3501 | page = fh->v4l_buffers.buffer[i].fbuffer_phys; |
3502 | if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, | 3502 | if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, |
3503 | todo, PAGE_SHARED)) { | 3503 | todo, PAGE_SHARED)) { |
3504 | dprintk(1, | 3504 | dprintk(1, |
3505 | KERN_ERR | 3505 | KERN_ERR |
3506 | "%s: zoran_mmap(V4L)i - remap_pfn_range failed\n", | 3506 | "%s: zoran_mmap(V4L)i - remap_pfn_range failed\n", |
3507 | ZR_DEVNAME(zr)); | 3507 | ZR_DEVNAME(zr)); |
3508 | res = -EAGAIN; | 3508 | res = -EAGAIN; |
3509 | goto v4l_mmap_unlock_and_return; | 3509 | goto v4l_mmap_unlock_and_return; |
3510 | } | 3510 | } |
3511 | size -= todo; | 3511 | size -= todo; |
3512 | start += todo; | 3512 | start += todo; |
3513 | fh->v4l_buffers.buffer[i].map = map; | 3513 | fh->v4l_buffers.buffer[i].map = map; |
3514 | if (size == 0) | 3514 | if (size == 0) |
3515 | break; | 3515 | break; |
3516 | } | 3516 | } |
3517 | v4l_mmap_unlock_and_return: | 3517 | v4l_mmap_unlock_and_return: |
3518 | mutex_unlock(&zr->resource_lock); | 3518 | mutex_unlock(&zr->resource_lock); |
3519 | 3519 | ||
3520 | break; | 3520 | break; |
3521 | 3521 | ||
3522 | default: | 3522 | default: |
3523 | dprintk(1, | 3523 | dprintk(1, |
3524 | KERN_ERR | 3524 | KERN_ERR |
3525 | "%s: zoran_mmap() - internal error - unknown map mode %d\n", | 3525 | "%s: zoran_mmap() - internal error - unknown map mode %d\n", |
3526 | ZR_DEVNAME(zr), fh->map_mode); | 3526 | ZR_DEVNAME(zr), fh->map_mode); |
3527 | break; | 3527 | break; |
3528 | } | 3528 | } |
3529 | 3529 | ||
3530 | return 0; | 3530 | return 0; |
3531 | } | 3531 | } |
3532 | 3532 | ||
3533 | static const struct v4l2_ioctl_ops zoran_ioctl_ops = { | 3533 | static const struct v4l2_ioctl_ops zoran_ioctl_ops = { |
3534 | .vidioc_querycap = zoran_querycap, | 3534 | .vidioc_querycap = zoran_querycap, |
3535 | .vidioc_cropcap = zoran_cropcap, | 3535 | .vidioc_cropcap = zoran_cropcap, |
3536 | .vidioc_s_crop = zoran_s_crop, | 3536 | .vidioc_s_crop = zoran_s_crop, |
3537 | .vidioc_g_crop = zoran_g_crop, | 3537 | .vidioc_g_crop = zoran_g_crop, |
3538 | .vidioc_enum_input = zoran_enum_input, | 3538 | .vidioc_enum_input = zoran_enum_input, |
3539 | .vidioc_g_input = zoran_g_input, | 3539 | .vidioc_g_input = zoran_g_input, |
3540 | .vidioc_s_input = zoran_s_input, | 3540 | .vidioc_s_input = zoran_s_input, |
3541 | .vidioc_enum_output = zoran_enum_output, | 3541 | .vidioc_enum_output = zoran_enum_output, |
3542 | .vidioc_g_output = zoran_g_output, | 3542 | .vidioc_g_output = zoran_g_output, |
3543 | .vidioc_s_output = zoran_s_output, | 3543 | .vidioc_s_output = zoran_s_output, |
3544 | .vidioc_g_fbuf = zoran_g_fbuf, | 3544 | .vidioc_g_fbuf = zoran_g_fbuf, |
3545 | .vidioc_s_fbuf = zoran_s_fbuf, | 3545 | .vidioc_s_fbuf = zoran_s_fbuf, |
3546 | .vidioc_g_std = zoran_g_std, | 3546 | .vidioc_g_std = zoran_g_std, |
3547 | .vidioc_s_std = zoran_s_std, | 3547 | .vidioc_s_std = zoran_s_std, |
3548 | .vidioc_g_jpegcomp = zoran_g_jpegcomp, | 3548 | .vidioc_g_jpegcomp = zoran_g_jpegcomp, |
3549 | .vidioc_s_jpegcomp = zoran_s_jpegcomp, | 3549 | .vidioc_s_jpegcomp = zoran_s_jpegcomp, |
3550 | .vidioc_overlay = zoran_overlay, | 3550 | .vidioc_overlay = zoran_overlay, |
3551 | .vidioc_reqbufs = zoran_reqbufs, | 3551 | .vidioc_reqbufs = zoran_reqbufs, |
3552 | .vidioc_querybuf = zoran_querybuf, | 3552 | .vidioc_querybuf = zoran_querybuf, |
3553 | .vidioc_qbuf = zoran_qbuf, | 3553 | .vidioc_qbuf = zoran_qbuf, |
3554 | .vidioc_dqbuf = zoran_dqbuf, | 3554 | .vidioc_dqbuf = zoran_dqbuf, |
3555 | .vidioc_streamon = zoran_streamon, | 3555 | .vidioc_streamon = zoran_streamon, |
3556 | .vidioc_streamoff = zoran_streamoff, | 3556 | .vidioc_streamoff = zoran_streamoff, |
3557 | .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, | 3557 | .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, |
3558 | .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out, | 3558 | .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out, |
3559 | .vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay, | 3559 | .vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay, |
3560 | .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, | 3560 | .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, |
3561 | .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out, | 3561 | .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out, |
3562 | .vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay, | 3562 | .vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay, |
3563 | .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, | 3563 | .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, |
3564 | .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out, | 3564 | .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out, |
3565 | .vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay, | 3565 | .vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay, |
3566 | .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, | 3566 | .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, |
3567 | .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out, | 3567 | .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out, |
3568 | .vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay, | 3568 | .vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay, |
3569 | .vidioc_queryctrl = zoran_queryctrl, | 3569 | .vidioc_queryctrl = zoran_queryctrl, |
3570 | .vidioc_s_ctrl = zoran_s_ctrl, | 3570 | .vidioc_s_ctrl = zoran_s_ctrl, |
3571 | .vidioc_g_ctrl = zoran_g_ctrl, | 3571 | .vidioc_g_ctrl = zoran_g_ctrl, |
3572 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 3572 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
3573 | .vidioc_default = zoran_default, | 3573 | .vidioc_default = zoran_default, |
3574 | .vidiocgmbuf = zoran_vidiocgmbuf, | 3574 | .vidiocgmbuf = zoran_vidiocgmbuf, |
3575 | #endif | 3575 | #endif |
3576 | }; | 3576 | }; |
3577 | 3577 | ||
3578 | static const struct v4l2_file_operations zoran_fops = { | 3578 | static const struct v4l2_file_operations zoran_fops = { |
3579 | .owner = THIS_MODULE, | 3579 | .owner = THIS_MODULE, |
3580 | .open = zoran_open, | 3580 | .open = zoran_open, |
3581 | .release = zoran_close, | 3581 | .release = zoran_close, |
3582 | .ioctl = video_ioctl2, | 3582 | .ioctl = video_ioctl2, |
3583 | .read = zoran_read, | 3583 | .read = zoran_read, |
3584 | .write = zoran_write, | 3584 | .write = zoran_write, |
3585 | .mmap = zoran_mmap, | 3585 | .mmap = zoran_mmap, |
3586 | .poll = zoran_poll, | 3586 | .poll = zoran_poll, |
3587 | }; | 3587 | }; |
3588 | 3588 | ||
3589 | struct video_device zoran_template __devinitdata = { | 3589 | struct video_device zoran_template __devinitdata = { |
3590 | .name = ZORAN_NAME, | 3590 | .name = ZORAN_NAME, |
3591 | .fops = &zoran_fops, | 3591 | .fops = &zoran_fops, |
3592 | .ioctl_ops = &zoran_ioctl_ops, | 3592 | .ioctl_ops = &zoran_ioctl_ops, |
3593 | .release = &zoran_vdev_release, | 3593 | .release = &zoran_vdev_release, |
3594 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, | 3594 | .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, |
3595 | .minor = -1 | 3595 | .minor = -1 |
3596 | }; | 3596 | }; |
3597 | 3597 | ||
3598 | 3598 |
include/linux/videodev.h
1 | /* | 1 | /* |
2 | * Video for Linux version 1 - OBSOLETE | 2 | * Video for Linux version 1 - OBSOLETE |
3 | * | 3 | * |
4 | * Header file for v4l1 drivers and applications, for | 4 | * Header file for v4l1 drivers and applications, for |
5 | * Linux kernels 2.2.x or 2.4.x. | 5 | * Linux kernels 2.2.x or 2.4.x. |
6 | * | 6 | * |
7 | * Provides header for legacy drivers and applications | 7 | * Provides header for legacy drivers and applications |
8 | * | 8 | * |
9 | * See http://linuxtv.org for more info | 9 | * See http://linuxtv.org for more info |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | #ifndef __LINUX_VIDEODEV_H | 12 | #ifndef __LINUX_VIDEODEV_H |
13 | #define __LINUX_VIDEODEV_H | 13 | #define __LINUX_VIDEODEV_H |
14 | 14 | ||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/ioctl.h> | 16 | #include <linux/ioctl.h> |
17 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
18 | 18 | ||
19 | #if defined(__MIN_V4L1) && defined (__KERNEL__) | ||
20 | |||
21 | /* | ||
22 | * Used by those V4L2 core functions that need a minimum V4L1 support, | ||
23 | * in order to allow V4L1 Compatibilty code compilation. | ||
24 | */ | ||
25 | |||
26 | struct video_mbuf | ||
27 | { | ||
28 | int size; /* Total memory to map */ | ||
29 | int frames; /* Frames */ | ||
30 | int offsets[VIDEO_MAX_FRAME]; | ||
31 | }; | ||
32 | |||
33 | #define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ | ||
34 | |||
35 | #else | ||
19 | #if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__) | 36 | #if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__) |
20 | 37 | ||
21 | #define VID_TYPE_CAPTURE 1 /* Can capture */ | 38 | #define VID_TYPE_CAPTURE 1 /* Can capture */ |
22 | #define VID_TYPE_TUNER 2 /* Can tune */ | 39 | #define VID_TYPE_TUNER 2 /* Can tune */ |
23 | #define VID_TYPE_TELETEXT 4 /* Does teletext */ | 40 | #define VID_TYPE_TELETEXT 4 /* Does teletext */ |
24 | #define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ | 41 | #define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ |
25 | #define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ | 42 | #define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ |
26 | #define VID_TYPE_CLIPPING 32 /* Can clip */ | 43 | #define VID_TYPE_CLIPPING 32 /* Can clip */ |
27 | #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ | 44 | #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ |
28 | #define VID_TYPE_SCALES 128 /* Scalable */ | 45 | #define VID_TYPE_SCALES 128 /* Scalable */ |
29 | #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ | 46 | #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ |
30 | #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ | 47 | #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ |
31 | #define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ | 48 | #define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ |
32 | #define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ | 49 | #define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ |
33 | #define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ | 50 | #define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ |
34 | #define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ | 51 | #define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ |
35 | 52 | ||
36 | struct video_capability | 53 | struct video_capability |
37 | { | 54 | { |
38 | char name[32]; | 55 | char name[32]; |
39 | int type; | 56 | int type; |
40 | int channels; /* Num channels */ | 57 | int channels; /* Num channels */ |
41 | int audios; /* Num audio devices */ | 58 | int audios; /* Num audio devices */ |
42 | int maxwidth; /* Supported width */ | 59 | int maxwidth; /* Supported width */ |
43 | int maxheight; /* And height */ | 60 | int maxheight; /* And height */ |
44 | int minwidth; /* Supported width */ | 61 | int minwidth; /* Supported width */ |
45 | int minheight; /* And height */ | 62 | int minheight; /* And height */ |
46 | }; | 63 | }; |
47 | 64 | ||
48 | 65 | ||
49 | struct video_channel | 66 | struct video_channel |
50 | { | 67 | { |
51 | int channel; | 68 | int channel; |
52 | char name[32]; | 69 | char name[32]; |
53 | int tuners; | 70 | int tuners; |
54 | __u32 flags; | 71 | __u32 flags; |
55 | #define VIDEO_VC_TUNER 1 /* Channel has a tuner */ | 72 | #define VIDEO_VC_TUNER 1 /* Channel has a tuner */ |
56 | #define VIDEO_VC_AUDIO 2 /* Channel has audio */ | 73 | #define VIDEO_VC_AUDIO 2 /* Channel has audio */ |
57 | __u16 type; | 74 | __u16 type; |
58 | #define VIDEO_TYPE_TV 1 | 75 | #define VIDEO_TYPE_TV 1 |
59 | #define VIDEO_TYPE_CAMERA 2 | 76 | #define VIDEO_TYPE_CAMERA 2 |
60 | __u16 norm; /* Norm set by channel */ | 77 | __u16 norm; /* Norm set by channel */ |
61 | }; | 78 | }; |
62 | 79 | ||
63 | struct video_tuner | 80 | struct video_tuner |
64 | { | 81 | { |
65 | int tuner; | 82 | int tuner; |
66 | char name[32]; | 83 | char name[32]; |
67 | unsigned long rangelow, rangehigh; /* Tuner range */ | 84 | unsigned long rangelow, rangehigh; /* Tuner range */ |
68 | __u32 flags; | 85 | __u32 flags; |
69 | #define VIDEO_TUNER_PAL 1 | 86 | #define VIDEO_TUNER_PAL 1 |
70 | #define VIDEO_TUNER_NTSC 2 | 87 | #define VIDEO_TUNER_NTSC 2 |
71 | #define VIDEO_TUNER_SECAM 4 | 88 | #define VIDEO_TUNER_SECAM 4 |
72 | #define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ | 89 | #define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ |
73 | #define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ | 90 | #define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ |
74 | #define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ | 91 | #define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ |
75 | #define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ | 92 | #define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ |
76 | #define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ | 93 | #define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ |
77 | __u16 mode; /* PAL/NTSC/SECAM/OTHER */ | 94 | __u16 mode; /* PAL/NTSC/SECAM/OTHER */ |
78 | #define VIDEO_MODE_PAL 0 | 95 | #define VIDEO_MODE_PAL 0 |
79 | #define VIDEO_MODE_NTSC 1 | 96 | #define VIDEO_MODE_NTSC 1 |
80 | #define VIDEO_MODE_SECAM 2 | 97 | #define VIDEO_MODE_SECAM 2 |
81 | #define VIDEO_MODE_AUTO 3 | 98 | #define VIDEO_MODE_AUTO 3 |
82 | __u16 signal; /* Signal strength 16bit scale */ | 99 | __u16 signal; /* Signal strength 16bit scale */ |
83 | }; | 100 | }; |
84 | 101 | ||
85 | struct video_picture | 102 | struct video_picture |
86 | { | 103 | { |
87 | __u16 brightness; | 104 | __u16 brightness; |
88 | __u16 hue; | 105 | __u16 hue; |
89 | __u16 colour; | 106 | __u16 colour; |
90 | __u16 contrast; | 107 | __u16 contrast; |
91 | __u16 whiteness; /* Black and white only */ | 108 | __u16 whiteness; /* Black and white only */ |
92 | __u16 depth; /* Capture depth */ | 109 | __u16 depth; /* Capture depth */ |
93 | __u16 palette; /* Palette in use */ | 110 | __u16 palette; /* Palette in use */ |
94 | #define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ | 111 | #define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ |
95 | #define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ | 112 | #define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ |
96 | #define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ | 113 | #define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ |
97 | #define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ | 114 | #define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ |
98 | #define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ | 115 | #define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ |
99 | #define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ | 116 | #define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ |
100 | #define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ | 117 | #define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ |
101 | #define VIDEO_PALETTE_YUYV 8 | 118 | #define VIDEO_PALETTE_YUYV 8 |
102 | #define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ | 119 | #define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ |
103 | #define VIDEO_PALETTE_YUV420 10 | 120 | #define VIDEO_PALETTE_YUV420 10 |
104 | #define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ | 121 | #define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ |
105 | #define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ | 122 | #define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ |
106 | #define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ | 123 | #define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ |
107 | #define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ | 124 | #define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ |
108 | #define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ | 125 | #define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ |
109 | #define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ | 126 | #define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ |
110 | #define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ | 127 | #define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ |
111 | #define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ | 128 | #define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ |
112 | }; | 129 | }; |
113 | 130 | ||
114 | struct video_audio | 131 | struct video_audio |
115 | { | 132 | { |
116 | int audio; /* Audio channel */ | 133 | int audio; /* Audio channel */ |
117 | __u16 volume; /* If settable */ | 134 | __u16 volume; /* If settable */ |
118 | __u16 bass, treble; | 135 | __u16 bass, treble; |
119 | __u32 flags; | 136 | __u32 flags; |
120 | #define VIDEO_AUDIO_MUTE 1 | 137 | #define VIDEO_AUDIO_MUTE 1 |
121 | #define VIDEO_AUDIO_MUTABLE 2 | 138 | #define VIDEO_AUDIO_MUTABLE 2 |
122 | #define VIDEO_AUDIO_VOLUME 4 | 139 | #define VIDEO_AUDIO_VOLUME 4 |
123 | #define VIDEO_AUDIO_BASS 8 | 140 | #define VIDEO_AUDIO_BASS 8 |
124 | #define VIDEO_AUDIO_TREBLE 16 | 141 | #define VIDEO_AUDIO_TREBLE 16 |
125 | #define VIDEO_AUDIO_BALANCE 32 | 142 | #define VIDEO_AUDIO_BALANCE 32 |
126 | char name[16]; | 143 | char name[16]; |
127 | #define VIDEO_SOUND_MONO 1 | 144 | #define VIDEO_SOUND_MONO 1 |
128 | #define VIDEO_SOUND_STEREO 2 | 145 | #define VIDEO_SOUND_STEREO 2 |
129 | #define VIDEO_SOUND_LANG1 4 | 146 | #define VIDEO_SOUND_LANG1 4 |
130 | #define VIDEO_SOUND_LANG2 8 | 147 | #define VIDEO_SOUND_LANG2 8 |
131 | __u16 mode; | 148 | __u16 mode; |
132 | __u16 balance; /* Stereo balance */ | 149 | __u16 balance; /* Stereo balance */ |
133 | __u16 step; /* Step actual volume uses */ | 150 | __u16 step; /* Step actual volume uses */ |
134 | }; | 151 | }; |
135 | 152 | ||
136 | struct video_clip | 153 | struct video_clip |
137 | { | 154 | { |
138 | __s32 x,y; | 155 | __s32 x,y; |
139 | __s32 width, height; | 156 | __s32 width, height; |
140 | struct video_clip *next; /* For user use/driver use only */ | 157 | struct video_clip *next; /* For user use/driver use only */ |
141 | }; | 158 | }; |
142 | 159 | ||
143 | struct video_window | 160 | struct video_window |
144 | { | 161 | { |
145 | __u32 x,y; /* Position of window */ | 162 | __u32 x,y; /* Position of window */ |
146 | __u32 width,height; /* Its size */ | 163 | __u32 width,height; /* Its size */ |
147 | __u32 chromakey; | 164 | __u32 chromakey; |
148 | __u32 flags; | 165 | __u32 flags; |
149 | struct video_clip __user *clips; /* Set only */ | 166 | struct video_clip __user *clips; /* Set only */ |
150 | int clipcount; | 167 | int clipcount; |
151 | #define VIDEO_WINDOW_INTERLACE 1 | 168 | #define VIDEO_WINDOW_INTERLACE 1 |
152 | #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ | 169 | #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ |
153 | #define VIDEO_CLIP_BITMAP -1 | 170 | #define VIDEO_CLIP_BITMAP -1 |
154 | /* bitmap is 1024x625, a '1' bit represents a clipped pixel */ | 171 | /* bitmap is 1024x625, a '1' bit represents a clipped pixel */ |
155 | #define VIDEO_CLIPMAP_SIZE (128 * 625) | 172 | #define VIDEO_CLIPMAP_SIZE (128 * 625) |
156 | }; | 173 | }; |
157 | 174 | ||
158 | struct video_capture | 175 | struct video_capture |
159 | { | 176 | { |
160 | __u32 x,y; /* Offsets into image */ | 177 | __u32 x,y; /* Offsets into image */ |
161 | __u32 width, height; /* Area to capture */ | 178 | __u32 width, height; /* Area to capture */ |
162 | __u16 decimation; /* Decimation divider */ | 179 | __u16 decimation; /* Decimation divider */ |
163 | __u16 flags; /* Flags for capture */ | 180 | __u16 flags; /* Flags for capture */ |
164 | #define VIDEO_CAPTURE_ODD 0 /* Temporal */ | 181 | #define VIDEO_CAPTURE_ODD 0 /* Temporal */ |
165 | #define VIDEO_CAPTURE_EVEN 1 | 182 | #define VIDEO_CAPTURE_EVEN 1 |
166 | }; | 183 | }; |
167 | 184 | ||
168 | struct video_buffer | 185 | struct video_buffer |
169 | { | 186 | { |
170 | void *base; | 187 | void *base; |
171 | int height,width; | 188 | int height,width; |
172 | int depth; | 189 | int depth; |
173 | int bytesperline; | 190 | int bytesperline; |
174 | }; | 191 | }; |
175 | 192 | ||
176 | struct video_mmap | 193 | struct video_mmap |
177 | { | 194 | { |
178 | unsigned int frame; /* Frame (0 - n) for double buffer */ | 195 | unsigned int frame; /* Frame (0 - n) for double buffer */ |
179 | int height,width; | 196 | int height,width; |
180 | unsigned int format; /* should be VIDEO_PALETTE_* */ | 197 | unsigned int format; /* should be VIDEO_PALETTE_* */ |
181 | }; | 198 | }; |
182 | 199 | ||
183 | struct video_key | 200 | struct video_key |
184 | { | 201 | { |
185 | __u8 key[8]; | 202 | __u8 key[8]; |
186 | __u32 flags; | 203 | __u32 flags; |
187 | }; | 204 | }; |
188 | 205 | ||
189 | struct video_mbuf | 206 | struct video_mbuf |
190 | { | 207 | { |
191 | int size; /* Total memory to map */ | 208 | int size; /* Total memory to map */ |
192 | int frames; /* Frames */ | 209 | int frames; /* Frames */ |
193 | int offsets[VIDEO_MAX_FRAME]; | 210 | int offsets[VIDEO_MAX_FRAME]; |
194 | }; | 211 | }; |
195 | 212 | ||
196 | #define VIDEO_NO_UNIT (-1) | 213 | #define VIDEO_NO_UNIT (-1) |
197 | 214 | ||
198 | struct video_unit | 215 | struct video_unit |
199 | { | 216 | { |
200 | int video; /* Video minor */ | 217 | int video; /* Video minor */ |
201 | int vbi; /* VBI minor */ | 218 | int vbi; /* VBI minor */ |
202 | int radio; /* Radio minor */ | 219 | int radio; /* Radio minor */ |
203 | int audio; /* Audio minor */ | 220 | int audio; /* Audio minor */ |
204 | int teletext; /* Teletext minor */ | 221 | int teletext; /* Teletext minor */ |
205 | }; | 222 | }; |
206 | 223 | ||
207 | struct vbi_format { | 224 | struct vbi_format { |
208 | __u32 sampling_rate; /* in Hz */ | 225 | __u32 sampling_rate; /* in Hz */ |
209 | __u32 samples_per_line; | 226 | __u32 samples_per_line; |
210 | __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ | 227 | __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ |
211 | __s32 start[2]; /* starting line for each frame */ | 228 | __s32 start[2]; /* starting line for each frame */ |
212 | __u32 count[2]; /* count of lines for each frame */ | 229 | __u32 count[2]; /* count of lines for each frame */ |
213 | __u32 flags; | 230 | __u32 flags; |
214 | #define VBI_UNSYNC 1 /* can distingues between top/bottom field */ | 231 | #define VBI_UNSYNC 1 /* can distingues between top/bottom field */ |
215 | #define VBI_INTERLACED 2 /* lines are interlaced */ | 232 | #define VBI_INTERLACED 2 /* lines are interlaced */ |
216 | }; | 233 | }; |
217 | 234 | ||
218 | /* video_info is biased towards hardware mpeg encode/decode */ | 235 | /* video_info is biased towards hardware mpeg encode/decode */ |
219 | /* but it could apply generically to any hardware compressor/decompressor */ | 236 | /* but it could apply generically to any hardware compressor/decompressor */ |
220 | struct video_info | 237 | struct video_info |
221 | { | 238 | { |
222 | __u32 frame_count; /* frames output since decode/encode began */ | 239 | __u32 frame_count; /* frames output since decode/encode began */ |
223 | __u32 h_size; /* current unscaled horizontal size */ | 240 | __u32 h_size; /* current unscaled horizontal size */ |
224 | __u32 v_size; /* current unscaled veritcal size */ | 241 | __u32 v_size; /* current unscaled veritcal size */ |
225 | __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ | 242 | __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ |
226 | __u32 picture_type; /* current picture type */ | 243 | __u32 picture_type; /* current picture type */ |
227 | __u32 temporal_reference; /* current temporal reference */ | 244 | __u32 temporal_reference; /* current temporal reference */ |
228 | __u8 user_data[256]; /* user data last found in compressed stream */ | 245 | __u8 user_data[256]; /* user data last found in compressed stream */ |
229 | /* user_data[0] contains user data flags, user_data[1] has count */ | 246 | /* user_data[0] contains user data flags, user_data[1] has count */ |
230 | }; | 247 | }; |
231 | 248 | ||
232 | /* generic structure for setting playback modes */ | 249 | /* generic structure for setting playback modes */ |
233 | struct video_play_mode | 250 | struct video_play_mode |
234 | { | 251 | { |
235 | int mode; | 252 | int mode; |
236 | int p1; | 253 | int p1; |
237 | int p2; | 254 | int p2; |
238 | }; | 255 | }; |
239 | 256 | ||
240 | /* for loading microcode / fpga programming */ | 257 | /* for loading microcode / fpga programming */ |
241 | struct video_code | 258 | struct video_code |
242 | { | 259 | { |
243 | char loadwhat[16]; /* name or tag of file being passed */ | 260 | char loadwhat[16]; /* name or tag of file being passed */ |
244 | int datasize; | 261 | int datasize; |
245 | __u8 *data; | 262 | __u8 *data; |
246 | }; | 263 | }; |
247 | 264 | ||
248 | #define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ | 265 | #define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ |
249 | #define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ | 266 | #define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ |
250 | #define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ | 267 | #define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ |
251 | #define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ | 268 | #define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ |
252 | #define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ | 269 | #define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ |
253 | #define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ | 270 | #define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ |
254 | #define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ | 271 | #define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ |
255 | #define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ | 272 | #define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ |
256 | #define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ | 273 | #define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ |
257 | #define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ | 274 | #define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ |
258 | #define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ | 275 | #define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ |
259 | #define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ | 276 | #define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ |
260 | #define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ | 277 | #define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ |
261 | #define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ | 278 | #define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ |
262 | #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ | 279 | #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ |
263 | #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ | 280 | #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ |
264 | #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ | 281 | #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ |
265 | #define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ | 282 | #define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ |
266 | #define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ | 283 | #define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ |
267 | #define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ | 284 | #define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ |
268 | #define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ | 285 | #define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ |
269 | #define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ | 286 | #define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ |
270 | #define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ | 287 | #define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ |
271 | #define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ | 288 | #define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ |
272 | #define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ | 289 | #define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ |
273 | #define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ | 290 | #define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ |
274 | #define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ | 291 | #define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ |
275 | #define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ | 292 | #define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ |
276 | #define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ | 293 | #define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ |
277 | 294 | ||
278 | 295 | ||
279 | #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ | 296 | #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ |
280 | 297 | ||
281 | /* VIDIOCSWRITEMODE */ | 298 | /* VIDIOCSWRITEMODE */ |
282 | #define VID_WRITE_MPEG_AUD 0 | 299 | #define VID_WRITE_MPEG_AUD 0 |
283 | #define VID_WRITE_MPEG_VID 1 | 300 | #define VID_WRITE_MPEG_VID 1 |
284 | #define VID_WRITE_OSD 2 | 301 | #define VID_WRITE_OSD 2 |
285 | #define VID_WRITE_TTX 3 | 302 | #define VID_WRITE_TTX 3 |
286 | #define VID_WRITE_CC 4 | 303 | #define VID_WRITE_CC 4 |
287 | #define VID_WRITE_MJPEG 5 | 304 | #define VID_WRITE_MJPEG 5 |
288 | 305 | ||
289 | /* VIDIOCSPLAYMODE */ | 306 | /* VIDIOCSPLAYMODE */ |
290 | #define VID_PLAY_VID_OUT_MODE 0 | 307 | #define VID_PLAY_VID_OUT_MODE 0 |
291 | /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ | 308 | /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ |
292 | #define VID_PLAY_GENLOCK 1 | 309 | #define VID_PLAY_GENLOCK 1 |
293 | /* p1: 0 = OFF, 1 = ON */ | 310 | /* p1: 0 = OFF, 1 = ON */ |
294 | /* p2: GENLOCK FINE DELAY value */ | 311 | /* p2: GENLOCK FINE DELAY value */ |
295 | #define VID_PLAY_NORMAL 2 | 312 | #define VID_PLAY_NORMAL 2 |
296 | #define VID_PLAY_PAUSE 3 | 313 | #define VID_PLAY_PAUSE 3 |
297 | #define VID_PLAY_SINGLE_FRAME 4 | 314 | #define VID_PLAY_SINGLE_FRAME 4 |
298 | #define VID_PLAY_FAST_FORWARD 5 | 315 | #define VID_PLAY_FAST_FORWARD 5 |
299 | #define VID_PLAY_SLOW_MOTION 6 | 316 | #define VID_PLAY_SLOW_MOTION 6 |
300 | #define VID_PLAY_IMMEDIATE_NORMAL 7 | 317 | #define VID_PLAY_IMMEDIATE_NORMAL 7 |
301 | #define VID_PLAY_SWITCH_CHANNELS 8 | 318 | #define VID_PLAY_SWITCH_CHANNELS 8 |
302 | #define VID_PLAY_FREEZE_FRAME 9 | 319 | #define VID_PLAY_FREEZE_FRAME 9 |
303 | #define VID_PLAY_STILL_MODE 10 | 320 | #define VID_PLAY_STILL_MODE 10 |
304 | #define VID_PLAY_MASTER_MODE 11 | 321 | #define VID_PLAY_MASTER_MODE 11 |
305 | /* p1: see below */ | 322 | /* p1: see below */ |
306 | #define VID_PLAY_MASTER_NONE 1 | 323 | #define VID_PLAY_MASTER_NONE 1 |
307 | #define VID_PLAY_MASTER_VIDEO 2 | 324 | #define VID_PLAY_MASTER_VIDEO 2 |
308 | #define VID_PLAY_MASTER_AUDIO 3 | 325 | #define VID_PLAY_MASTER_AUDIO 3 |
309 | #define VID_PLAY_ACTIVE_SCANLINES 12 | 326 | #define VID_PLAY_ACTIVE_SCANLINES 12 |
310 | /* p1 = first active; p2 = last active */ | 327 | /* p1 = first active; p2 = last active */ |
311 | #define VID_PLAY_RESET 13 | 328 | #define VID_PLAY_RESET 13 |
312 | #define VID_PLAY_END_MARK 14 | 329 | #define VID_PLAY_END_MARK 14 |
313 | 330 | ||
314 | #endif /* CONFIG_VIDEO_V4L1_COMPAT */ | 331 | #endif /* CONFIG_VIDEO_V4L1_COMPAT */ |
332 | #endif /* __MIN_V4L1 */ | ||
315 | 333 | ||
316 | #endif /* __LINUX_VIDEODEV_H */ | 334 | #endif /* __LINUX_VIDEODEV_H */ |
317 | 335 | ||
318 | /* | 336 | /* |
319 | * Local variables: | 337 | * Local variables: |
320 | * c-basic-offset: 8 | 338 | * c-basic-offset: 8 |
321 | * End: | 339 | * End: |
322 | */ | 340 | */ |
323 | 341 |
include/media/v4l2-ioctl.h
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * V 4 L 2 D R I V E R H E L P E R A P I | 3 | * V 4 L 2 D R I V E R H E L P E R A P I |
4 | * | 4 | * |
5 | * Moved from videodev2.h | 5 | * Moved from videodev2.h |
6 | * | 6 | * |
7 | * Some commonly needed functions for drivers (v4l2-common.o module) | 7 | * Some commonly needed functions for drivers (v4l2-common.o module) |
8 | */ | 8 | */ |
9 | #ifndef _V4L2_IOCTL_H | 9 | #ifndef _V4L2_IOCTL_H |
10 | #define _V4L2_IOCTL_H | 10 | #define _V4L2_IOCTL_H |
11 | 11 | ||
12 | #include <linux/poll.h> | 12 | #include <linux/poll.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/mutex.h> | 15 | #include <linux/mutex.h> |
16 | #include <linux/compiler.h> /* need __user */ | 16 | #include <linux/compiler.h> /* need __user */ |
17 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 17 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
18 | #define __MIN_V4L1 | ||
18 | #include <linux/videodev.h> | 19 | #include <linux/videodev.h> |
19 | #else | 20 | #else |
20 | #include <linux/videodev2.h> | 21 | #include <linux/videodev2.h> |
21 | #endif | 22 | #endif |
22 | 23 | ||
23 | struct v4l2_ioctl_ops { | 24 | struct v4l2_ioctl_ops { |
24 | /* ioctl callbacks */ | 25 | /* ioctl callbacks */ |
25 | 26 | ||
26 | /* VIDIOC_QUERYCAP handler */ | 27 | /* VIDIOC_QUERYCAP handler */ |
27 | int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); | 28 | int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); |
28 | 29 | ||
29 | /* Priority handling */ | 30 | /* Priority handling */ |
30 | int (*vidioc_g_priority) (struct file *file, void *fh, | 31 | int (*vidioc_g_priority) (struct file *file, void *fh, |
31 | enum v4l2_priority *p); | 32 | enum v4l2_priority *p); |
32 | int (*vidioc_s_priority) (struct file *file, void *fh, | 33 | int (*vidioc_s_priority) (struct file *file, void *fh, |
33 | enum v4l2_priority p); | 34 | enum v4l2_priority p); |
34 | 35 | ||
35 | /* VIDIOC_ENUM_FMT handlers */ | 36 | /* VIDIOC_ENUM_FMT handlers */ |
36 | int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, | 37 | int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, |
37 | struct v4l2_fmtdesc *f); | 38 | struct v4l2_fmtdesc *f); |
38 | int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, | 39 | int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, |
39 | struct v4l2_fmtdesc *f); | 40 | struct v4l2_fmtdesc *f); |
40 | int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh, | 41 | int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh, |
41 | struct v4l2_fmtdesc *f); | 42 | struct v4l2_fmtdesc *f); |
42 | int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, | 43 | int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, |
43 | struct v4l2_fmtdesc *f); | 44 | struct v4l2_fmtdesc *f); |
44 | 45 | ||
45 | /* VIDIOC_G_FMT handlers */ | 46 | /* VIDIOC_G_FMT handlers */ |
46 | int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh, | 47 | int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh, |
47 | struct v4l2_format *f); | 48 | struct v4l2_format *f); |
48 | int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, | 49 | int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, |
49 | struct v4l2_format *f); | 50 | struct v4l2_format *f); |
50 | int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh, | 51 | int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh, |
51 | struct v4l2_format *f); | 52 | struct v4l2_format *f); |
52 | int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, | 53 | int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, |
53 | struct v4l2_format *f); | 54 | struct v4l2_format *f); |
54 | int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh, | 55 | int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh, |
55 | struct v4l2_format *f); | 56 | struct v4l2_format *f); |
56 | int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh, | 57 | int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh, |
57 | struct v4l2_format *f); | 58 | struct v4l2_format *f); |
58 | int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, | 59 | int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, |
59 | struct v4l2_format *f); | 60 | struct v4l2_format *f); |
60 | int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, | 61 | int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, |
61 | struct v4l2_format *f); | 62 | struct v4l2_format *f); |
62 | int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, | 63 | int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, |
63 | struct v4l2_format *f); | 64 | struct v4l2_format *f); |
64 | 65 | ||
65 | /* VIDIOC_S_FMT handlers */ | 66 | /* VIDIOC_S_FMT handlers */ |
66 | int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, | 67 | int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, |
67 | struct v4l2_format *f); | 68 | struct v4l2_format *f); |
68 | int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, | 69 | int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, |
69 | struct v4l2_format *f); | 70 | struct v4l2_format *f); |
70 | int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh, | 71 | int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh, |
71 | struct v4l2_format *f); | 72 | struct v4l2_format *f); |
72 | int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, | 73 | int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, |
73 | struct v4l2_format *f); | 74 | struct v4l2_format *f); |
74 | int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh, | 75 | int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh, |
75 | struct v4l2_format *f); | 76 | struct v4l2_format *f); |
76 | int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh, | 77 | int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh, |
77 | struct v4l2_format *f); | 78 | struct v4l2_format *f); |
78 | int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, | 79 | int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, |
79 | struct v4l2_format *f); | 80 | struct v4l2_format *f); |
80 | int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, | 81 | int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, |
81 | struct v4l2_format *f); | 82 | struct v4l2_format *f); |
82 | int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, | 83 | int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, |
83 | struct v4l2_format *f); | 84 | struct v4l2_format *f); |
84 | 85 | ||
85 | /* VIDIOC_TRY_FMT handlers */ | 86 | /* VIDIOC_TRY_FMT handlers */ |
86 | int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh, | 87 | int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh, |
87 | struct v4l2_format *f); | 88 | struct v4l2_format *f); |
88 | int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, | 89 | int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, |
89 | struct v4l2_format *f); | 90 | struct v4l2_format *f); |
90 | int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh, | 91 | int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh, |
91 | struct v4l2_format *f); | 92 | struct v4l2_format *f); |
92 | int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, | 93 | int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, |
93 | struct v4l2_format *f); | 94 | struct v4l2_format *f); |
94 | int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh, | 95 | int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh, |
95 | struct v4l2_format *f); | 96 | struct v4l2_format *f); |
96 | int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh, | 97 | int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh, |
97 | struct v4l2_format *f); | 98 | struct v4l2_format *f); |
98 | int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, | 99 | int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, |
99 | struct v4l2_format *f); | 100 | struct v4l2_format *f); |
100 | int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, | 101 | int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, |
101 | struct v4l2_format *f); | 102 | struct v4l2_format *f); |
102 | int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, | 103 | int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, |
103 | struct v4l2_format *f); | 104 | struct v4l2_format *f); |
104 | 105 | ||
105 | /* Buffer handlers */ | 106 | /* Buffer handlers */ |
106 | int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b); | 107 | int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b); |
107 | int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); | 108 | int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); |
108 | int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); | 109 | int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); |
109 | int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); | 110 | int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); |
110 | 111 | ||
111 | 112 | ||
112 | int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); | 113 | int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); |
113 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 114 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
114 | /* buffer type is struct vidio_mbuf * */ | 115 | /* buffer type is struct vidio_mbuf * */ |
115 | int (*vidiocgmbuf) (struct file *file, void *fh, struct video_mbuf *p); | 116 | int (*vidiocgmbuf) (struct file *file, void *fh, struct video_mbuf *p); |
116 | #endif | 117 | #endif |
117 | int (*vidioc_g_fbuf) (struct file *file, void *fh, | 118 | int (*vidioc_g_fbuf) (struct file *file, void *fh, |
118 | struct v4l2_framebuffer *a); | 119 | struct v4l2_framebuffer *a); |
119 | int (*vidioc_s_fbuf) (struct file *file, void *fh, | 120 | int (*vidioc_s_fbuf) (struct file *file, void *fh, |
120 | struct v4l2_framebuffer *a); | 121 | struct v4l2_framebuffer *a); |
121 | 122 | ||
122 | /* Stream on/off */ | 123 | /* Stream on/off */ |
123 | int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i); | 124 | int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i); |
124 | int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i); | 125 | int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i); |
125 | 126 | ||
126 | /* Standard handling | 127 | /* Standard handling |
127 | ENUMSTD is handled by videodev.c | 128 | ENUMSTD is handled by videodev.c |
128 | */ | 129 | */ |
129 | int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); | 130 | int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); |
130 | int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); | 131 | int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); |
131 | int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); | 132 | int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); |
132 | 133 | ||
133 | /* Input handling */ | 134 | /* Input handling */ |
134 | int (*vidioc_enum_input)(struct file *file, void *fh, | 135 | int (*vidioc_enum_input)(struct file *file, void *fh, |
135 | struct v4l2_input *inp); | 136 | struct v4l2_input *inp); |
136 | int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i); | 137 | int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i); |
137 | int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i); | 138 | int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i); |
138 | 139 | ||
139 | /* Output handling */ | 140 | /* Output handling */ |
140 | int (*vidioc_enum_output) (struct file *file, void *fh, | 141 | int (*vidioc_enum_output) (struct file *file, void *fh, |
141 | struct v4l2_output *a); | 142 | struct v4l2_output *a); |
142 | int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i); | 143 | int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i); |
143 | int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i); | 144 | int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i); |
144 | 145 | ||
145 | /* Control handling */ | 146 | /* Control handling */ |
146 | int (*vidioc_queryctrl) (struct file *file, void *fh, | 147 | int (*vidioc_queryctrl) (struct file *file, void *fh, |
147 | struct v4l2_queryctrl *a); | 148 | struct v4l2_queryctrl *a); |
148 | int (*vidioc_g_ctrl) (struct file *file, void *fh, | 149 | int (*vidioc_g_ctrl) (struct file *file, void *fh, |
149 | struct v4l2_control *a); | 150 | struct v4l2_control *a); |
150 | int (*vidioc_s_ctrl) (struct file *file, void *fh, | 151 | int (*vidioc_s_ctrl) (struct file *file, void *fh, |
151 | struct v4l2_control *a); | 152 | struct v4l2_control *a); |
152 | int (*vidioc_g_ext_ctrls) (struct file *file, void *fh, | 153 | int (*vidioc_g_ext_ctrls) (struct file *file, void *fh, |
153 | struct v4l2_ext_controls *a); | 154 | struct v4l2_ext_controls *a); |
154 | int (*vidioc_s_ext_ctrls) (struct file *file, void *fh, | 155 | int (*vidioc_s_ext_ctrls) (struct file *file, void *fh, |
155 | struct v4l2_ext_controls *a); | 156 | struct v4l2_ext_controls *a); |
156 | int (*vidioc_try_ext_ctrls) (struct file *file, void *fh, | 157 | int (*vidioc_try_ext_ctrls) (struct file *file, void *fh, |
157 | struct v4l2_ext_controls *a); | 158 | struct v4l2_ext_controls *a); |
158 | int (*vidioc_querymenu) (struct file *file, void *fh, | 159 | int (*vidioc_querymenu) (struct file *file, void *fh, |
159 | struct v4l2_querymenu *a); | 160 | struct v4l2_querymenu *a); |
160 | 161 | ||
161 | /* Audio ioctls */ | 162 | /* Audio ioctls */ |
162 | int (*vidioc_enumaudio) (struct file *file, void *fh, | 163 | int (*vidioc_enumaudio) (struct file *file, void *fh, |
163 | struct v4l2_audio *a); | 164 | struct v4l2_audio *a); |
164 | int (*vidioc_g_audio) (struct file *file, void *fh, | 165 | int (*vidioc_g_audio) (struct file *file, void *fh, |
165 | struct v4l2_audio *a); | 166 | struct v4l2_audio *a); |
166 | int (*vidioc_s_audio) (struct file *file, void *fh, | 167 | int (*vidioc_s_audio) (struct file *file, void *fh, |
167 | struct v4l2_audio *a); | 168 | struct v4l2_audio *a); |
168 | 169 | ||
169 | /* Audio out ioctls */ | 170 | /* Audio out ioctls */ |
170 | int (*vidioc_enumaudout) (struct file *file, void *fh, | 171 | int (*vidioc_enumaudout) (struct file *file, void *fh, |
171 | struct v4l2_audioout *a); | 172 | struct v4l2_audioout *a); |
172 | int (*vidioc_g_audout) (struct file *file, void *fh, | 173 | int (*vidioc_g_audout) (struct file *file, void *fh, |
173 | struct v4l2_audioout *a); | 174 | struct v4l2_audioout *a); |
174 | int (*vidioc_s_audout) (struct file *file, void *fh, | 175 | int (*vidioc_s_audout) (struct file *file, void *fh, |
175 | struct v4l2_audioout *a); | 176 | struct v4l2_audioout *a); |
176 | int (*vidioc_g_modulator) (struct file *file, void *fh, | 177 | int (*vidioc_g_modulator) (struct file *file, void *fh, |
177 | struct v4l2_modulator *a); | 178 | struct v4l2_modulator *a); |
178 | int (*vidioc_s_modulator) (struct file *file, void *fh, | 179 | int (*vidioc_s_modulator) (struct file *file, void *fh, |
179 | struct v4l2_modulator *a); | 180 | struct v4l2_modulator *a); |
180 | /* Crop ioctls */ | 181 | /* Crop ioctls */ |
181 | int (*vidioc_cropcap) (struct file *file, void *fh, | 182 | int (*vidioc_cropcap) (struct file *file, void *fh, |
182 | struct v4l2_cropcap *a); | 183 | struct v4l2_cropcap *a); |
183 | int (*vidioc_g_crop) (struct file *file, void *fh, | 184 | int (*vidioc_g_crop) (struct file *file, void *fh, |
184 | struct v4l2_crop *a); | 185 | struct v4l2_crop *a); |
185 | int (*vidioc_s_crop) (struct file *file, void *fh, | 186 | int (*vidioc_s_crop) (struct file *file, void *fh, |
186 | struct v4l2_crop *a); | 187 | struct v4l2_crop *a); |
187 | /* Compression ioctls */ | 188 | /* Compression ioctls */ |
188 | int (*vidioc_g_jpegcomp) (struct file *file, void *fh, | 189 | int (*vidioc_g_jpegcomp) (struct file *file, void *fh, |
189 | struct v4l2_jpegcompression *a); | 190 | struct v4l2_jpegcompression *a); |
190 | int (*vidioc_s_jpegcomp) (struct file *file, void *fh, | 191 | int (*vidioc_s_jpegcomp) (struct file *file, void *fh, |
191 | struct v4l2_jpegcompression *a); | 192 | struct v4l2_jpegcompression *a); |
192 | int (*vidioc_g_enc_index) (struct file *file, void *fh, | 193 | int (*vidioc_g_enc_index) (struct file *file, void *fh, |
193 | struct v4l2_enc_idx *a); | 194 | struct v4l2_enc_idx *a); |
194 | int (*vidioc_encoder_cmd) (struct file *file, void *fh, | 195 | int (*vidioc_encoder_cmd) (struct file *file, void *fh, |
195 | struct v4l2_encoder_cmd *a); | 196 | struct v4l2_encoder_cmd *a); |
196 | int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, | 197 | int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, |
197 | struct v4l2_encoder_cmd *a); | 198 | struct v4l2_encoder_cmd *a); |
198 | 199 | ||
199 | /* Stream type-dependent parameter ioctls */ | 200 | /* Stream type-dependent parameter ioctls */ |
200 | int (*vidioc_g_parm) (struct file *file, void *fh, | 201 | int (*vidioc_g_parm) (struct file *file, void *fh, |
201 | struct v4l2_streamparm *a); | 202 | struct v4l2_streamparm *a); |
202 | int (*vidioc_s_parm) (struct file *file, void *fh, | 203 | int (*vidioc_s_parm) (struct file *file, void *fh, |
203 | struct v4l2_streamparm *a); | 204 | struct v4l2_streamparm *a); |
204 | 205 | ||
205 | /* Tuner ioctls */ | 206 | /* Tuner ioctls */ |
206 | int (*vidioc_g_tuner) (struct file *file, void *fh, | 207 | int (*vidioc_g_tuner) (struct file *file, void *fh, |
207 | struct v4l2_tuner *a); | 208 | struct v4l2_tuner *a); |
208 | int (*vidioc_s_tuner) (struct file *file, void *fh, | 209 | int (*vidioc_s_tuner) (struct file *file, void *fh, |
209 | struct v4l2_tuner *a); | 210 | struct v4l2_tuner *a); |
210 | int (*vidioc_g_frequency) (struct file *file, void *fh, | 211 | int (*vidioc_g_frequency) (struct file *file, void *fh, |
211 | struct v4l2_frequency *a); | 212 | struct v4l2_frequency *a); |
212 | int (*vidioc_s_frequency) (struct file *file, void *fh, | 213 | int (*vidioc_s_frequency) (struct file *file, void *fh, |
213 | struct v4l2_frequency *a); | 214 | struct v4l2_frequency *a); |
214 | 215 | ||
215 | /* Sliced VBI cap */ | 216 | /* Sliced VBI cap */ |
216 | int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh, | 217 | int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh, |
217 | struct v4l2_sliced_vbi_cap *a); | 218 | struct v4l2_sliced_vbi_cap *a); |
218 | 219 | ||
219 | /* Log status ioctl */ | 220 | /* Log status ioctl */ |
220 | int (*vidioc_log_status) (struct file *file, void *fh); | 221 | int (*vidioc_log_status) (struct file *file, void *fh); |
221 | 222 | ||
222 | int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh, | 223 | int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh, |
223 | struct v4l2_hw_freq_seek *a); | 224 | struct v4l2_hw_freq_seek *a); |
224 | 225 | ||
225 | /* Debugging ioctls */ | 226 | /* Debugging ioctls */ |
226 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 227 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
227 | int (*vidioc_g_register) (struct file *file, void *fh, | 228 | int (*vidioc_g_register) (struct file *file, void *fh, |
228 | struct v4l2_dbg_register *reg); | 229 | struct v4l2_dbg_register *reg); |
229 | int (*vidioc_s_register) (struct file *file, void *fh, | 230 | int (*vidioc_s_register) (struct file *file, void *fh, |
230 | struct v4l2_dbg_register *reg); | 231 | struct v4l2_dbg_register *reg); |
231 | #endif | 232 | #endif |
232 | int (*vidioc_g_chip_ident) (struct file *file, void *fh, | 233 | int (*vidioc_g_chip_ident) (struct file *file, void *fh, |
233 | struct v4l2_dbg_chip_ident *chip); | 234 | struct v4l2_dbg_chip_ident *chip); |
234 | 235 | ||
235 | int (*vidioc_enum_framesizes) (struct file *file, void *fh, | 236 | int (*vidioc_enum_framesizes) (struct file *file, void *fh, |
236 | struct v4l2_frmsizeenum *fsize); | 237 | struct v4l2_frmsizeenum *fsize); |
237 | 238 | ||
238 | int (*vidioc_enum_frameintervals) (struct file *file, void *fh, | 239 | int (*vidioc_enum_frameintervals) (struct file *file, void *fh, |
239 | struct v4l2_frmivalenum *fival); | 240 | struct v4l2_frmivalenum *fival); |
240 | 241 | ||
241 | /* For other private ioctls */ | 242 | /* For other private ioctls */ |
242 | long (*vidioc_default) (struct file *file, void *fh, | 243 | long (*vidioc_default) (struct file *file, void *fh, |
243 | int cmd, void *arg); | 244 | int cmd, void *arg); |
244 | }; | 245 | }; |
245 | 246 | ||
246 | 247 | ||
247 | /* v4l debugging and diagnostics */ | 248 | /* v4l debugging and diagnostics */ |
248 | 249 | ||
249 | /* Debug bitmask flags to be used on V4L2 */ | 250 | /* Debug bitmask flags to be used on V4L2 */ |
250 | #define V4L2_DEBUG_IOCTL 0x01 | 251 | #define V4L2_DEBUG_IOCTL 0x01 |
251 | #define V4L2_DEBUG_IOCTL_ARG 0x02 | 252 | #define V4L2_DEBUG_IOCTL_ARG 0x02 |
252 | 253 | ||
253 | /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */ | 254 | /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */ |
254 | #define v4l_print_ioctl(name, cmd) \ | 255 | #define v4l_print_ioctl(name, cmd) \ |
255 | do { \ | 256 | do { \ |
256 | printk(KERN_DEBUG "%s: ", name); \ | 257 | printk(KERN_DEBUG "%s: ", name); \ |
257 | v4l_printk_ioctl(cmd); \ | 258 | v4l_printk_ioctl(cmd); \ |
258 | } while (0) | 259 | } while (0) |
259 | 260 | ||
260 | /* Use this macro in I2C drivers where 'client' is the struct i2c_client | 261 | /* Use this macro in I2C drivers where 'client' is the struct i2c_client |
261 | pointer */ | 262 | pointer */ |
262 | #define v4l_i2c_print_ioctl(client, cmd) \ | 263 | #define v4l_i2c_print_ioctl(client, cmd) \ |
263 | do { \ | 264 | do { \ |
264 | v4l_client_printk(KERN_DEBUG, client, ""); \ | 265 | v4l_client_printk(KERN_DEBUG, client, ""); \ |
265 | v4l_printk_ioctl(cmd); \ | 266 | v4l_printk_ioctl(cmd); \ |
266 | } while (0) | 267 | } while (0) |
267 | 268 | ||
268 | /* Video standard functions */ | 269 | /* Video standard functions */ |
269 | extern const char *v4l2_norm_to_name(v4l2_std_id id); | 270 | extern const char *v4l2_norm_to_name(v4l2_std_id id); |
270 | extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod); | 271 | extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod); |
271 | extern int v4l2_video_std_construct(struct v4l2_standard *vs, | 272 | extern int v4l2_video_std_construct(struct v4l2_standard *vs, |
272 | int id, const char *name); | 273 | int id, const char *name); |
273 | /* Prints the ioctl in a human-readable format */ | 274 | /* Prints the ioctl in a human-readable format */ |
274 | extern void v4l_printk_ioctl(unsigned int cmd); | 275 | extern void v4l_printk_ioctl(unsigned int cmd); |
275 | 276 | ||
276 | /* names for fancy debug output */ | 277 | /* names for fancy debug output */ |
277 | extern const char *v4l2_field_names[]; | 278 | extern const char *v4l2_field_names[]; |
278 | extern const char *v4l2_type_names[]; | 279 | extern const char *v4l2_type_names[]; |
279 | 280 | ||
280 | /* Compatibility layer interface -- v4l1-compat module */ | 281 | /* Compatibility layer interface -- v4l1-compat module */ |
281 | typedef long (*v4l2_kioctl)(struct file *file, | 282 | typedef long (*v4l2_kioctl)(struct file *file, |
282 | unsigned int cmd, void *arg); | 283 | unsigned int cmd, void *arg); |
283 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 284 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
284 | long v4l_compat_translate_ioctl(struct file *file, | 285 | long v4l_compat_translate_ioctl(struct file *file, |
285 | int cmd, void *arg, v4l2_kioctl driver_ioctl); | 286 | int cmd, void *arg, v4l2_kioctl driver_ioctl); |
286 | #else | 287 | #else |
287 | #define v4l_compat_translate_ioctl(file, cmd, arg, ioctl) (-EINVAL) | 288 | #define v4l_compat_translate_ioctl(file, cmd, arg, ioctl) (-EINVAL) |
288 | #endif | 289 | #endif |
289 | 290 | ||
290 | #ifdef CONFIG_COMPAT | 291 | #ifdef CONFIG_COMPAT |
291 | /* 32 Bits compatibility layer for 64 bits processors */ | 292 | /* 32 Bits compatibility layer for 64 bits processors */ |
292 | extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, | 293 | extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, |
293 | unsigned long arg); | 294 | unsigned long arg); |
294 | #endif | 295 | #endif |
295 | 296 | ||
296 | /* Include support for obsoleted stuff */ | 297 | /* Include support for obsoleted stuff */ |
297 | extern long video_usercopy(struct file *file, unsigned int cmd, | 298 | extern long video_usercopy(struct file *file, unsigned int cmd, |
298 | unsigned long arg, v4l2_kioctl func); | 299 | unsigned long arg, v4l2_kioctl func); |
299 | 300 | ||
300 | /* Standard handlers for V4L ioctl's */ | 301 | /* Standard handlers for V4L ioctl's */ |
301 | extern long video_ioctl2(struct file *file, | 302 | extern long video_ioctl2(struct file *file, |
302 | unsigned int cmd, unsigned long arg); | 303 | unsigned int cmd, unsigned long arg); |
303 | 304 | ||
304 | #endif /* _V4L2_IOCTL_H */ | 305 | #endif /* _V4L2_IOCTL_H */ |
305 | 306 |