diff options
author | Devin Heitmueller <devin.heitmueller@gmail.com> | 2008-06-28 07:57:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:12:48 -0400 |
commit | a9fc52bcbeb5245b58d23c558f3e3e8f18bebbc3 (patch) | |
tree | bd0f1f54ed1ee0f3994a38ecebe6dc5fb00c4bc5 | |
parent | 305519c924d8f2f2f85c390c6d456dc41dbe0284 (diff) |
V4L/DVB (8123): Add support for em2860 based PointNix Intra-Oral Camera
em28xx-cards.c
em28xx-input.c
em28xx-video.c
em28xx.h
- Add support for the PointNix Intra-Oral Camera, which required addition of
a construct for reading the "snapshot" button (provided on the em2860 and
em2880 chips, but this is the first case where I have seen it actually used
in a product). The button is wired to pin 56 on the em2880.
http://www.pointnix.com/ENG/dental/product_02.asp
Thanks to Roberto Mantovani <rmantovani@libero.it> for testing the changes
Signed-off-by: Devin Heitmueller <devin.heitmueller@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | Documentation/video4linux/CARDLIST.em28xx | 1 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-cards.c | 18 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-input.c | 87 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 2 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 10 |
5 files changed, 118 insertions, 0 deletions
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index c7e23942c1dc..10591467ef16 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx | |||
@@ -17,3 +17,4 @@ | |||
17 | 16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513,2040:6517,2040:651b,2040:651f] | 17 | 16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513,2040:6517,2040:651b,2040:651f] |
18 | 17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227] | 18 | 17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227] |
19 | 18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502] | 19 | 18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502] |
20 | 19 -> PointNix Intra-Oral Camera (em2860) | ||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 938c51e1c86d..05f0d5a15058 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -426,6 +426,19 @@ struct em28xx_board em28xx_boards[] = { | |||
426 | .amux = EM28XX_AMUX_LINE_IN, | 426 | .amux = EM28XX_AMUX_LINE_IN, |
427 | } }, | 427 | } }, |
428 | }, | 428 | }, |
429 | [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { | ||
430 | .name = "PointNix Intra-Oral Camera", | ||
431 | .has_snapshot_button = 1, | ||
432 | .vchannels = 1, | ||
433 | .tda9887_conf = TDA9887_PRESENT, | ||
434 | .tuner_type = TUNER_ABSENT, | ||
435 | .decoder = EM28XX_SAA7113, | ||
436 | .input = { { | ||
437 | .type = EM28XX_VMUX_SVIDEO, | ||
438 | .vmux = SAA7115_SVIDEO3, | ||
439 | .amux = 0, | ||
440 | } }, | ||
441 | }, | ||
429 | }; | 442 | }; |
430 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); | 443 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); |
431 | 444 | ||
@@ -522,6 +535,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash [] = { | |||
522 | static struct em28xx_hash_table em28xx_i2c_hash[] = { | 535 | static struct em28xx_hash_table em28xx_i2c_hash[] = { |
523 | {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, | 536 | {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, |
524 | {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, | 537 | {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, |
538 | {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT}, | ||
525 | }; | 539 | }; |
526 | 540 | ||
527 | int em28xx_tuner_callback(void *ptr, int command, int arg) | 541 | int em28xx_tuner_callback(void *ptr, int command, int arg) |
@@ -554,6 +568,7 @@ static void em28xx_set_model(struct em28xx *dev) | |||
554 | dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; | 568 | dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; |
555 | dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; | 569 | dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; |
556 | dev->has_dvb = em28xx_boards[dev->model].has_dvb; | 570 | dev->has_dvb = em28xx_boards[dev->model].has_dvb; |
571 | dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; | ||
557 | } | 572 | } |
558 | 573 | ||
559 | /* Since em28xx_pre_card_setup() requires a proper dev->model, | 574 | /* Since em28xx_pre_card_setup() requires a proper dev->model, |
@@ -841,6 +856,9 @@ void em28xx_card_setup(struct em28xx *dev) | |||
841 | em28xx_set_model(dev); | 856 | em28xx_set_model(dev); |
842 | } | 857 | } |
843 | 858 | ||
859 | if (dev->has_snapshot_button) | ||
860 | em28xx_register_snapshot_button(dev); | ||
861 | |||
844 | /* Allow override tuner type by a module parameter */ | 862 | /* Allow override tuner type by a module parameter */ |
845 | if (tuner >= 0) | 863 | if (tuner >= 0) |
846 | dev->tuner_type = tuner; | 864 | dev->tuner_type = tuner; |
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index bb5807159b8d..eab3d9511af3 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c | |||
@@ -30,6 +30,10 @@ | |||
30 | 30 | ||
31 | #include "em28xx.h" | 31 | #include "em28xx.h" |
32 | 32 | ||
33 | #define EM28XX_SNAPSHOT_KEY KEY_CAMERA | ||
34 | #define EM28XX_SBUTTON_QUERY_INTERVAL 500 | ||
35 | #define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 | ||
36 | |||
33 | static unsigned int ir_debug; | 37 | static unsigned int ir_debug; |
34 | module_param(ir_debug, int, 0644); | 38 | module_param(ir_debug, int, 0644); |
35 | MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); | 39 | MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); |
@@ -124,6 +128,89 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, | |||
124 | return 1; | 128 | return 1; |
125 | } | 129 | } |
126 | 130 | ||
131 | static void em28xx_query_sbutton(struct work_struct *work) | ||
132 | { | ||
133 | /* Poll the register and see if the button is depressed */ | ||
134 | struct em28xx *dev = | ||
135 | container_of(work, struct em28xx, sbutton_query_work.work); | ||
136 | int ret; | ||
137 | |||
138 | ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); | ||
139 | |||
140 | if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { | ||
141 | u8 cleared; | ||
142 | /* Button is depressed, clear the register */ | ||
143 | cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; | ||
144 | em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); | ||
145 | |||
146 | /* Not emulate the keypress */ | ||
147 | input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, | ||
148 | 1); | ||
149 | /* Now unpress the key */ | ||
150 | input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, | ||
151 | 0); | ||
152 | } | ||
153 | |||
154 | /* Schedule next poll */ | ||
155 | schedule_delayed_work(&dev->sbutton_query_work, | ||
156 | msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); | ||
157 | } | ||
158 | |||
159 | void em28xx_register_snapshot_button(struct em28xx *dev) | ||
160 | { | ||
161 | struct input_dev *input_dev; | ||
162 | int err; | ||
163 | |||
164 | em28xx_info("Registering snapshot button...\n"); | ||
165 | input_dev = input_allocate_device(); | ||
166 | if (!input_dev) { | ||
167 | em28xx_errdev("input_allocate_device failed\n"); | ||
168 | return; | ||
169 | } | ||
170 | |||
171 | usb_make_path(dev->udev, dev->snapshot_button_path, | ||
172 | sizeof(dev->snapshot_button_path)); | ||
173 | strlcat(dev->snapshot_button_path, "/sbutton", | ||
174 | sizeof(dev->snapshot_button_path)); | ||
175 | INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); | ||
176 | |||
177 | input_dev->name = "em28xx snapshot button"; | ||
178 | input_dev->phys = dev->snapshot_button_path; | ||
179 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | ||
180 | set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); | ||
181 | input_dev->keycodesize = 0; | ||
182 | input_dev->keycodemax = 0; | ||
183 | input_dev->id.bustype = BUS_USB; | ||
184 | input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); | ||
185 | input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); | ||
186 | input_dev->id.version = 1; | ||
187 | input_dev->dev.parent = &dev->udev->dev; | ||
188 | |||
189 | err = input_register_device(input_dev); | ||
190 | if (err) { | ||
191 | em28xx_errdev("input_register_device failed\n"); | ||
192 | input_free_device(input_dev); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | dev->sbutton_input_dev = input_dev; | ||
197 | schedule_delayed_work(&dev->sbutton_query_work, | ||
198 | msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); | ||
199 | return; | ||
200 | |||
201 | } | ||
202 | |||
203 | void em28xx_deregister_snapshot_button(struct em28xx *dev) | ||
204 | { | ||
205 | if (dev->sbutton_input_dev != NULL) { | ||
206 | em28xx_info("Deregistering snapshot button\n"); | ||
207 | cancel_rearming_delayed_work(&dev->sbutton_query_work); | ||
208 | input_unregister_device(dev->sbutton_input_dev); | ||
209 | dev->sbutton_input_dev = NULL; | ||
210 | } | ||
211 | return; | ||
212 | } | ||
213 | |||
127 | /* ---------------------------------------------------------------------- | 214 | /* ---------------------------------------------------------------------- |
128 | * Local variables: | 215 | * Local variables: |
129 | * c-basic-offset: 8 | 216 | * c-basic-offset: 8 |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 1c3e8b6291ea..2d9f14d2a00b 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -1590,6 +1590,8 @@ static void em28xx_release_resources(struct em28xx *dev) | |||
1590 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, | 1590 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, |
1591 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); | 1591 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); |
1592 | list_del(&dev->devlist); | 1592 | list_del(&dev->devlist); |
1593 | if (dev->sbutton_input_dev) | ||
1594 | em28xx_deregister_snapshot_button(dev); | ||
1593 | if (dev->radio_dev) { | 1595 | if (dev->radio_dev) { |
1594 | if (-1 != dev->radio_dev->minor) | 1596 | if (-1 != dev->radio_dev->minor) |
1595 | video_unregister_device(dev->radio_dev); | 1597 | video_unregister_device(dev->radio_dev); |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index cff618b2d13c..89842c5d64a1 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -57,6 +57,7 @@ | |||
57 | #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 | 57 | #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 |
58 | #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 | 58 | #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 |
59 | #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 | 59 | #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 |
60 | #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 | ||
60 | 61 | ||
61 | /* Limits minimum and default number of buffers */ | 62 | /* Limits minimum and default number of buffers */ |
62 | #define EM28XX_MIN_BUF 4 | 63 | #define EM28XX_MIN_BUF 4 |
@@ -249,6 +250,7 @@ struct em28xx_board { | |||
249 | unsigned int has_12mhz_i2s:1; | 250 | unsigned int has_12mhz_i2s:1; |
250 | unsigned int max_range_640_480:1; | 251 | unsigned int max_range_640_480:1; |
251 | unsigned int has_dvb:1; | 252 | unsigned int has_dvb:1; |
253 | unsigned int has_snapshot_button:1; | ||
252 | 254 | ||
253 | enum em28xx_decoder decoder; | 255 | enum em28xx_decoder decoder; |
254 | 256 | ||
@@ -328,6 +330,7 @@ struct em28xx { | |||
328 | unsigned int has_12mhz_i2s:1; | 330 | unsigned int has_12mhz_i2s:1; |
329 | unsigned int max_range_640_480:1; | 331 | unsigned int max_range_640_480:1; |
330 | unsigned int has_dvb:1; | 332 | unsigned int has_dvb:1; |
333 | unsigned int has_snapshot_button:1; | ||
331 | 334 | ||
332 | /* Some older em28xx chips needs a waiting time after writing */ | 335 | /* Some older em28xx chips needs a waiting time after writing */ |
333 | unsigned int wait_after_write; | 336 | unsigned int wait_after_write; |
@@ -418,6 +421,11 @@ struct em28xx { | |||
418 | /* Caches GPO and GPIO registers */ | 421 | /* Caches GPO and GPIO registers */ |
419 | unsigned char reg_gpo, reg_gpio; | 422 | unsigned char reg_gpo, reg_gpio; |
420 | 423 | ||
424 | /* Snapshot button */ | ||
425 | char snapshot_button_path[30]; /* path of the input dev */ | ||
426 | struct input_dev *sbutton_input_dev; | ||
427 | struct delayed_work sbutton_query_work; | ||
428 | |||
421 | struct em28xx_dvb *dvb; | 429 | struct em28xx_dvb *dvb; |
422 | }; | 430 | }; |
423 | 431 | ||
@@ -483,6 +491,8 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); | |||
483 | int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); | 491 | int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); |
484 | int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, | 492 | int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, |
485 | u32 *ir_raw); | 493 | u32 *ir_raw); |
494 | void em28xx_register_snapshot_button(struct em28xx *dev); | ||
495 | void em28xx_deregister_snapshot_button(struct em28xx *dev); | ||
486 | 496 | ||
487 | /* printk macros */ | 497 | /* printk macros */ |
488 | 498 | ||