diff options
-rw-r--r-- | drivers/media/video/cx88/cx88-blackbird.c | 178 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-dvb.c | 197 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-mpeg.c | 344 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 46 |
5 files changed, 591 insertions, 176 deletions
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 46738321adaf..0037188d77d4 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -50,7 +50,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); | |||
50 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | 50 | #define dprintk(level,fmt, arg...) if (debug >= level) \ |
51 | printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) | 51 | printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) |
52 | 52 | ||
53 | static LIST_HEAD(cx8802_devlist); | ||
54 | 53 | ||
55 | /* ------------------------------------------------------------------ */ | 54 | /* ------------------------------------------------------------------ */ |
56 | 55 | ||
@@ -882,7 +881,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, | |||
882 | BLACKBIRD_MPEG_CAPTURE, | 881 | BLACKBIRD_MPEG_CAPTURE, |
883 | BLACKBIRD_RAW_BITS_NONE); | 882 | BLACKBIRD_RAW_BITS_NONE); |
884 | 883 | ||
885 | cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); | 884 | cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); |
886 | 885 | ||
887 | blackbird_initialize_codec(dev); | 886 | blackbird_initialize_codec(dev); |
888 | cx88_set_scale(dev->core, dev->width, dev->height, | 887 | cx88_set_scale(dev->core, dev->width, dev->height, |
@@ -914,11 +913,15 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, | |||
914 | } | 913 | } |
915 | 914 | ||
916 | default: | 915 | default: |
917 | return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); | 916 | return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); |
918 | } | 917 | } |
919 | return 0; | 918 | return 0; |
920 | } | 919 | } |
921 | 920 | ||
921 | int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
922 | unsigned int cmd, void *arg); | ||
923 | unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
924 | |||
922 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) | 925 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) |
923 | { | 926 | { |
924 | return cmd; | 927 | return cmd; |
@@ -927,33 +930,48 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd) | |||
927 | static int mpeg_ioctl(struct inode *inode, struct file *file, | 930 | static int mpeg_ioctl(struct inode *inode, struct file *file, |
928 | unsigned int cmd, unsigned long arg) | 931 | unsigned int cmd, unsigned long arg) |
929 | { | 932 | { |
930 | cmd = mpeg_translate_ioctl( cmd ); | 933 | cmd = cx88_ioctl_translator( cmd ); |
931 | return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); | 934 | return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); |
932 | } | 935 | } |
933 | 936 | ||
934 | static int mpeg_open(struct inode *inode, struct file *file) | 937 | static int mpeg_open(struct inode *inode, struct file *file) |
935 | { | 938 | { |
936 | int minor = iminor(inode); | 939 | int minor = iminor(inode); |
937 | struct cx8802_dev *h,*dev = NULL; | 940 | struct cx8802_dev *dev = NULL; |
938 | struct cx8802_fh *fh; | 941 | struct cx8802_fh *fh; |
939 | struct list_head *list; | 942 | struct cx8802_driver *drv = NULL; |
943 | int err; | ||
940 | 944 | ||
941 | list_for_each(list,&cx8802_devlist) { | 945 | dprintk( 1, "%s\n", __FUNCTION__); |
942 | h = list_entry(list, struct cx8802_dev, devlist); | 946 | |
943 | if (h->mpeg_dev->minor == minor) | 947 | dev = cx8802_get_device(inode); |
944 | dev = h; | 948 | if (dev == NULL) |
945 | } | ||
946 | if (NULL == dev) | ||
947 | return -ENODEV; | 949 | return -ENODEV; |
948 | 950 | ||
949 | if (blackbird_initialize_codec(dev) < 0) | 951 | /* Make sure we can acquire the hardware */ |
952 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | ||
953 | if (drv) { | ||
954 | err = drv->request_acquire(drv); | ||
955 | if(err != 0) { | ||
956 | dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err); | ||
957 | return err; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | if (blackbird_initialize_codec(dev) < 0) { | ||
962 | if (drv) | ||
963 | drv->request_release(drv); | ||
950 | return -EINVAL; | 964 | return -EINVAL; |
965 | } | ||
951 | dprintk(1,"open minor=%d\n",minor); | 966 | dprintk(1,"open minor=%d\n",minor); |
952 | 967 | ||
953 | /* allocate + initialize per filehandle data */ | 968 | /* allocate + initialize per filehandle data */ |
954 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 969 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
955 | if (NULL == fh) | 970 | if (NULL == fh) { |
971 | if (drv) | ||
972 | drv->request_release(drv); | ||
956 | return -ENOMEM; | 973 | return -ENOMEM; |
974 | } | ||
957 | file->private_data = fh; | 975 | file->private_data = fh; |
958 | fh->dev = dev; | 976 | fh->dev = dev; |
959 | 977 | ||
@@ -974,6 +992,8 @@ static int mpeg_open(struct inode *inode, struct file *file) | |||
974 | static int mpeg_release(struct inode *inode, struct file *file) | 992 | static int mpeg_release(struct inode *inode, struct file *file) |
975 | { | 993 | { |
976 | struct cx8802_fh *fh = file->private_data; | 994 | struct cx8802_fh *fh = file->private_data; |
995 | struct cx8802_dev *dev = NULL; | ||
996 | struct cx8802_driver *drv = NULL; | ||
977 | 997 | ||
978 | /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ | 998 | /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ |
979 | blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, | 999 | blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, |
@@ -992,6 +1012,16 @@ static int mpeg_release(struct inode *inode, struct file *file) | |||
992 | videobuf_mmap_free(&fh->mpegq); | 1012 | videobuf_mmap_free(&fh->mpegq); |
993 | file->private_data = NULL; | 1013 | file->private_data = NULL; |
994 | kfree(fh); | 1014 | kfree(fh); |
1015 | |||
1016 | /* Make sure we release the hardware */ | ||
1017 | dev = cx8802_get_device(inode); | ||
1018 | if (dev == NULL) | ||
1019 | return -ENODEV; | ||
1020 | |||
1021 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | ||
1022 | if (drv) | ||
1023 | drv->request_release(drv); | ||
1024 | |||
995 | return 0; | 1025 | return 0; |
996 | } | 1026 | } |
997 | 1027 | ||
@@ -1043,6 +1073,44 @@ static struct video_device cx8802_mpeg_template = | |||
1043 | 1073 | ||
1044 | /* ------------------------------------------------------------------ */ | 1074 | /* ------------------------------------------------------------------ */ |
1045 | 1075 | ||
1076 | /* The CX8802 MPEG API will call this when we can use the hardware */ | ||
1077 | static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) | ||
1078 | { | ||
1079 | struct cx88_core *core = drv->core; | ||
1080 | int err = 0; | ||
1081 | |||
1082 | switch (core->board) { | ||
1083 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
1084 | /* By default, core setup will leave the cx22702 out of reset, on the bus. | ||
1085 | * We left the hardware on power up with the cx22702 active. | ||
1086 | * We're being given access to re-arrange the GPIOs. | ||
1087 | * Take the bus off the cx22702 and put the cx23416 on it. | ||
1088 | */ | ||
1089 | cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */ | ||
1090 | cx_set(MO_GP0_IO, 0x00000004); /* Disable the cx22702 */ | ||
1091 | break; | ||
1092 | default: | ||
1093 | err = -ENODEV; | ||
1094 | } | ||
1095 | return err; | ||
1096 | } | ||
1097 | |||
1098 | /* The CX8802 MPEG API will call this when we need to release the hardware */ | ||
1099 | static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) | ||
1100 | { | ||
1101 | struct cx88_core *core = drv->core; | ||
1102 | int err = 0; | ||
1103 | |||
1104 | switch (core->board) { | ||
1105 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
1106 | /* Exit leaving the cx23416 on the bus */ | ||
1107 | break; | ||
1108 | default: | ||
1109 | err = -ENODEV; | ||
1110 | } | ||
1111 | return err; | ||
1112 | } | ||
1113 | |||
1046 | static void blackbird_unregister_video(struct cx8802_dev *dev) | 1114 | static void blackbird_unregister_video(struct cx8802_dev *dev) |
1047 | { | 1115 | { |
1048 | if (dev->mpeg_dev) { | 1116 | if (dev->mpeg_dev) { |
@@ -1073,28 +1141,23 @@ static int blackbird_register_video(struct cx8802_dev *dev) | |||
1073 | 1141 | ||
1074 | /* ----------------------------------------------------------- */ | 1142 | /* ----------------------------------------------------------- */ |
1075 | 1143 | ||
1076 | static int __devinit blackbird_probe(struct pci_dev *pci_dev, | 1144 | static int cx8802_blackbird_probe(struct cx8802_driver *drv) |
1077 | const struct pci_device_id *pci_id) | ||
1078 | { | 1145 | { |
1079 | struct cx8802_dev *dev; | 1146 | struct cx88_core *core = drv->core; |
1080 | struct cx88_core *core; | 1147 | struct cx8802_dev *dev = core->dvbdev; |
1081 | int err; | 1148 | int err; |
1082 | 1149 | ||
1083 | /* general setup */ | 1150 | dprintk( 1, "%s\n", __FUNCTION__); |
1084 | core = cx88_core_get(pci_dev); | 1151 | dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", |
1085 | if (NULL == core) | 1152 | core->board, |
1086 | return -EINVAL; | 1153 | core->name, |
1154 | core->pci_bus, | ||
1155 | core->pci_slot); | ||
1087 | 1156 | ||
1088 | err = -ENODEV; | 1157 | err = -ENODEV; |
1089 | if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) | 1158 | if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) |
1090 | goto fail_core; | 1159 | goto fail_core; |
1091 | 1160 | ||
1092 | err = -ENOMEM; | ||
1093 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | ||
1094 | if (NULL == dev) | ||
1095 | goto fail_core; | ||
1096 | dev->pci = pci_dev; | ||
1097 | dev->core = core; | ||
1098 | dev->width = 720; | 1161 | dev->width = 720; |
1099 | dev->height = 576; | 1162 | dev->height = 576; |
1100 | cx2341x_fill_defaults(&dev->params); | 1163 | cx2341x_fill_defaults(&dev->params); |
@@ -1106,64 +1169,36 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, | |||
1106 | dev->height = 576; | 1169 | dev->height = 576; |
1107 | } | 1170 | } |
1108 | 1171 | ||
1109 | err = cx8802_init_common(dev); | ||
1110 | if (0 != err) | ||
1111 | goto fail_free; | ||
1112 | |||
1113 | /* blackbird stuff */ | 1172 | /* blackbird stuff */ |
1114 | printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", | 1173 | printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", |
1115 | core->name); | 1174 | core->name); |
1116 | host_setup(dev->core); | 1175 | host_setup(dev->core); |
1117 | 1176 | ||
1118 | list_add_tail(&dev->devlist,&cx8802_devlist); | ||
1119 | blackbird_register_video(dev); | 1177 | blackbird_register_video(dev); |
1120 | 1178 | ||
1121 | /* initial device configuration: needed ? */ | 1179 | /* initial device configuration: needed ? */ |
1122 | 1180 | ||
1123 | return 0; | 1181 | return 0; |
1124 | 1182 | ||
1125 | fail_free: | ||
1126 | kfree(dev); | ||
1127 | fail_core: | 1183 | fail_core: |
1128 | cx88_core_put(core,pci_dev); | ||
1129 | return err; | 1184 | return err; |
1130 | } | 1185 | } |
1131 | 1186 | ||
1132 | static void __devexit blackbird_remove(struct pci_dev *pci_dev) | 1187 | static int cx8802_blackbird_remove(struct cx8802_driver *drv) |
1133 | { | 1188 | { |
1134 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); | ||
1135 | |||
1136 | /* blackbird */ | 1189 | /* blackbird */ |
1137 | blackbird_unregister_video(dev); | 1190 | blackbird_unregister_video(drv->core->dvbdev); |
1138 | list_del(&dev->devlist); | ||
1139 | 1191 | ||
1140 | /* common */ | 1192 | return 0; |
1141 | cx8802_fini_common(dev); | ||
1142 | cx88_core_put(dev->core,dev->pci); | ||
1143 | kfree(dev); | ||
1144 | } | 1193 | } |
1145 | 1194 | ||
1146 | static struct pci_device_id cx8802_pci_tbl[] = { | 1195 | static struct cx8802_driver cx8802_blackbird_driver = { |
1147 | { | 1196 | .type_id = CX88_MPEG_BLACKBIRD, |
1148 | .vendor = 0x14f1, | 1197 | .hw_access = CX8802_DRVCTL_SHARED, |
1149 | .device = 0x8802, | 1198 | .probe = cx8802_blackbird_probe, |
1150 | .subvendor = PCI_ANY_ID, | 1199 | .remove = cx8802_blackbird_remove, |
1151 | .subdevice = PCI_ANY_ID, | 1200 | .advise_acquire = cx8802_blackbird_advise_acquire, |
1152 | },{ | 1201 | .advise_release = cx8802_blackbird_advise_release, |
1153 | /* --- end of list --- */ | ||
1154 | } | ||
1155 | }; | ||
1156 | MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); | ||
1157 | |||
1158 | static struct pci_driver blackbird_pci_driver = { | ||
1159 | .name = "cx88-blackbird", | ||
1160 | .id_table = cx8802_pci_tbl, | ||
1161 | .probe = blackbird_probe, | ||
1162 | .remove = __devexit_p(blackbird_remove), | ||
1163 | #ifdef CONFIG_PM | ||
1164 | .suspend = cx8802_suspend_common, | ||
1165 | .resume = cx8802_resume_common, | ||
1166 | #endif | ||
1167 | }; | 1202 | }; |
1168 | 1203 | ||
1169 | static int blackbird_init(void) | 1204 | static int blackbird_init(void) |
@@ -1176,17 +1211,22 @@ static int blackbird_init(void) | |||
1176 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 1211 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
1177 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 1212 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
1178 | #endif | 1213 | #endif |
1179 | return pci_register_driver(&blackbird_pci_driver); | 1214 | cx88_ioctl_hook = mpeg_do_ioctl; |
1215 | cx88_ioctl_translator = mpeg_translate_ioctl; | ||
1216 | return cx8802_register_driver(&cx8802_blackbird_driver); | ||
1180 | } | 1217 | } |
1181 | 1218 | ||
1182 | static void blackbird_fini(void) | 1219 | static void blackbird_fini(void) |
1183 | { | 1220 | { |
1184 | pci_unregister_driver(&blackbird_pci_driver); | 1221 | cx8802_unregister_driver(&cx8802_blackbird_driver); |
1185 | } | 1222 | } |
1186 | 1223 | ||
1187 | module_init(blackbird_init); | 1224 | module_init(blackbird_init); |
1188 | module_exit(blackbird_fini); | 1225 | module_exit(blackbird_fini); |
1189 | 1226 | ||
1227 | EXPORT_SYMBOL(cx88_ioctl_hook); | ||
1228 | EXPORT_SYMBOL(cx88_ioctl_translator); | ||
1229 | |||
1190 | /* ----------------------------------------------------------- */ | 1230 | /* ----------------------------------------------------------- */ |
1191 | /* | 1231 | /* |
1192 | * Local variables: | 1232 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f764a57c56be..1c5db2070a6e 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -1303,7 +1303,7 @@ struct cx88_board cx88_boards[] = { | |||
1303 | .gpio0 = 0xe780, | 1303 | .gpio0 = 0xe780, |
1304 | }}, | 1304 | }}, |
1305 | /* fixme: Add radio support */ | 1305 | /* fixme: Add radio support */ |
1306 | .mpeg = CX88_MPEG_DVB, | 1306 | .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, |
1307 | }, | 1307 | }, |
1308 | }; | 1308 | }; |
1309 | const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); | 1309 | const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); |
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 0ef13e7efa2e..8150c09cd2c0 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -57,7 +57,7 @@ module_param(debug, int, 0644); | |||
57 | MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); | 57 | MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); |
58 | 58 | ||
59 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | 59 | #define dprintk(level,fmt, arg...) if (debug >= level) \ |
60 | printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg) | 60 | printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) |
61 | 61 | ||
62 | /* ------------------------------------------------------------------ */ | 62 | /* ------------------------------------------------------------------ */ |
63 | 63 | ||
@@ -315,20 +315,36 @@ static struct cx22702_config hauppauge_novat_config = { | |||
315 | .demod_address = 0x43, | 315 | .demod_address = 0x43, |
316 | .output_mode = CX22702_SERIAL_OUTPUT, | 316 | .output_mode = CX22702_SERIAL_OUTPUT, |
317 | }; | 317 | }; |
318 | |||
319 | static struct cx22702_config hauppauge_hvr1100_config = { | 318 | static struct cx22702_config hauppauge_hvr1100_config = { |
320 | .demod_address = 0x63, | 319 | .demod_address = 0x63, |
321 | .output_mode = CX22702_SERIAL_OUTPUT, | 320 | .output_mode = CX22702_SERIAL_OUTPUT, |
322 | }; | 321 | }; |
323 | 322 | static struct cx22702_config hauppauge_hvr3000_config = { | |
324 | static struct cx22702_config hauppauge_hvr1300_config = { | ||
325 | .demod_address = 0x63, | 323 | .demod_address = 0x63, |
326 | .output_mode = CX22702_SERIAL_OUTPUT, | 324 | .output_mode = CX22702_SERIAL_OUTPUT, |
327 | }; | 325 | }; |
328 | 326 | ||
329 | static struct cx22702_config hauppauge_hvr3000_config = { | 327 | static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, |
328 | int acquire) | ||
329 | { | ||
330 | struct cx8802_dev *dev= fe->dvb->priv; | ||
331 | struct cx8802_driver *drv = NULL; | ||
332 | int ret = 0; | ||
333 | |||
334 | drv = cx8802_get_driver(dev, CX88_MPEG_DVB); | ||
335 | if (drv) { | ||
336 | if(acquire) | ||
337 | ret = drv->request_acquire(drv); | ||
338 | else | ||
339 | ret = drv->request_release(drv); | ||
340 | } | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | static struct cx22702_config hauppauge_hvr1300_config = { | ||
330 | .demod_address = 0x63, | 346 | .demod_address = 0x63, |
331 | .output_mode = CX22702_SERIAL_OUTPUT, | 347 | .output_mode = CX22702_SERIAL_OUTPUT, |
332 | }; | 348 | }; |
333 | 349 | ||
334 | static int or51132_set_ts_param(struct dvb_frontend* fe, | 350 | static int or51132_set_ts_param(struct dvb_frontend* fe, |
@@ -555,26 +571,6 @@ static int dvb_register(struct cx8802_dev *dev) | |||
555 | &dvb_pll_fmd1216me); | 571 | &dvb_pll_fmd1216me); |
556 | } | 572 | } |
557 | break; | 573 | break; |
558 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
559 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
560 | &hauppauge_hvr1300_config, | ||
561 | &dev->core->i2c_adap); | ||
562 | if (dev->dvb.frontend != NULL) { | ||
563 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
564 | &dev->core->i2c_adap, | ||
565 | &dvb_pll_fmd1216me); | ||
566 | } | ||
567 | break; | ||
568 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
569 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
570 | &hauppauge_hvr3000_config, | ||
571 | &dev->core->i2c_adap); | ||
572 | if (dev->dvb.frontend != NULL) { | ||
573 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
574 | &dev->core->i2c_adap, | ||
575 | &dvb_pll_fmd1216me); | ||
576 | } | ||
577 | break; | ||
578 | case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: | 574 | case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: |
579 | dev->dvb.frontend = dvb_attach(mt352_attach, | 575 | dev->dvb.frontend = dvb_attach(mt352_attach, |
580 | &dvico_fusionhdtv, | 576 | &dvico_fusionhdtv, |
@@ -782,6 +778,26 @@ static int dvb_register(struct cx8802_dev *dev) | |||
782 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; | 778 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; |
783 | } | 779 | } |
784 | break; | 780 | break; |
781 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
782 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
783 | &hauppauge_hvr1300_config, | ||
784 | &dev->core->i2c_adap); | ||
785 | if (dev->dvb.frontend != NULL) { | ||
786 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
787 | &dev->core->i2c_adap, | ||
788 | &dvb_pll_fmd1216me); | ||
789 | } | ||
790 | break; | ||
791 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
792 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
793 | &hauppauge_hvr3000_config, | ||
794 | &dev->core->i2c_adap); | ||
795 | if (dev->dvb.frontend != NULL) { | ||
796 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
797 | &dev->core->i2c_adap, | ||
798 | &dvb_pll_fmd1216me); | ||
799 | } | ||
800 | break; | ||
785 | default: | 801 | default: |
786 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", | 802 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", |
787 | dev->core->name); | 803 | dev->core->name); |
@@ -796,6 +812,8 @@ static int dvb_register(struct cx8802_dev *dev) | |||
796 | dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min; | 812 | dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min; |
797 | dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max; | 813 | dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max; |
798 | } | 814 | } |
815 | /* Ensure all frontends negotiate bus access */ | ||
816 | dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; | ||
799 | 817 | ||
800 | /* Put the analog decoder in standby to keep it quiet */ | 818 | /* Put the analog decoder in standby to keep it quiet */ |
801 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); | 819 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); |
@@ -806,37 +824,67 @@ static int dvb_register(struct cx8802_dev *dev) | |||
806 | 824 | ||
807 | /* ----------------------------------------------------------- */ | 825 | /* ----------------------------------------------------------- */ |
808 | 826 | ||
809 | static int __devinit dvb_probe(struct pci_dev *pci_dev, | 827 | /* CX8802 MPEG -> mini driver - We have been given the hardware */ |
810 | const struct pci_device_id *pci_id) | 828 | static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) |
811 | { | 829 | { |
812 | struct cx8802_dev *dev; | 830 | struct cx88_core *core = drv->core; |
813 | struct cx88_core *core; | 831 | int err = 0; |
832 | dprintk( 1, "%s\n", __FUNCTION__); | ||
833 | |||
834 | switch (core->board) { | ||
835 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
836 | /* We arrive here with either the cx23416 or the cx22702 | ||
837 | * on the bus. Take the bus from the cx23416 and enable the | ||
838 | * cx22702 demod | ||
839 | */ | ||
840 | cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset and enable */ | ||
841 | cx_clear(MO_GP0_IO, 0x00000004); | ||
842 | udelay(1000); | ||
843 | break; | ||
844 | default: | ||
845 | err = -ENODEV; | ||
846 | } | ||
847 | return err; | ||
848 | } | ||
849 | |||
850 | /* CX8802 MPEG -> mini driver - We no longer have the hardware */ | ||
851 | static int cx8802_dvb_advise_release(struct cx8802_driver *drv) | ||
852 | { | ||
853 | struct cx88_core *core = drv->core; | ||
854 | int err = 0; | ||
855 | dprintk( 1, "%s\n", __FUNCTION__); | ||
856 | |||
857 | switch (core->board) { | ||
858 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
859 | /* Do Nothing, leave the cx22702 on the bus. */ | ||
860 | break; | ||
861 | default: | ||
862 | err = -ENODEV; | ||
863 | } | ||
864 | return err; | ||
865 | } | ||
866 | |||
867 | static int cx8802_dvb_probe(struct cx8802_driver *drv) | ||
868 | { | ||
869 | struct cx88_core *core = drv->core; | ||
870 | struct cx8802_dev *dev = drv->core->dvbdev; | ||
814 | int err; | 871 | int err; |
815 | 872 | ||
816 | /* general setup */ | 873 | dprintk( 1, "%s\n", __FUNCTION__); |
817 | core = cx88_core_get(pci_dev); | 874 | dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", |
818 | if (NULL == core) | 875 | core->board, |
819 | return -EINVAL; | 876 | core->name, |
877 | core->pci_bus, | ||
878 | core->pci_slot); | ||
820 | 879 | ||
821 | err = -ENODEV; | 880 | err = -ENODEV; |
822 | if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) | 881 | if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) |
823 | goto fail_core; | 882 | goto fail_core; |
824 | 883 | ||
825 | err = -ENOMEM; | ||
826 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | ||
827 | if (NULL == dev) | ||
828 | goto fail_core; | ||
829 | dev->pci = pci_dev; | ||
830 | dev->core = core; | ||
831 | |||
832 | err = cx8802_init_common(dev); | ||
833 | if (0 != err) | ||
834 | goto fail_free; | ||
835 | |||
836 | #ifdef HAVE_VP3054_I2C | 884 | #ifdef HAVE_VP3054_I2C |
837 | err = vp3054_i2c_probe(dev); | 885 | err = vp3054_i2c_probe(dev); |
838 | if (0 != err) | 886 | if (0 != err) |
839 | goto fail_free; | 887 | goto fail_core; |
840 | #endif | 888 | #endif |
841 | 889 | ||
842 | /* dvb stuff */ | 890 | /* dvb stuff */ |
@@ -848,28 +896,16 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, | |||
848 | sizeof(struct cx88_buffer), | 896 | sizeof(struct cx88_buffer), |
849 | dev); | 897 | dev); |
850 | err = dvb_register(dev); | 898 | err = dvb_register(dev); |
851 | if (0 != err) | 899 | if (err != 0) |
852 | goto fail_fini; | 900 | printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); |
853 | |||
854 | /* Maintain a reference to cx88-video can query the 8802 device. */ | ||
855 | core->dvbdev = dev; | ||
856 | return 0; | ||
857 | 901 | ||
858 | fail_fini: | ||
859 | cx8802_fini_common(dev); | ||
860 | fail_free: | ||
861 | kfree(dev); | ||
862 | fail_core: | 902 | fail_core: |
863 | cx88_core_put(core,pci_dev); | ||
864 | return err; | 903 | return err; |
865 | } | 904 | } |
866 | 905 | ||
867 | static void __devexit dvb_remove(struct pci_dev *pci_dev) | 906 | static int cx8802_dvb_remove(struct cx8802_driver *drv) |
868 | { | 907 | { |
869 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); | 908 | struct cx8802_dev *dev = drv->core->dvbdev; |
870 | |||
871 | /* Destroy any 8802 reference. */ | ||
872 | dev->core->dvbdev = NULL; | ||
873 | 909 | ||
874 | /* dvb */ | 910 | /* dvb */ |
875 | videobuf_dvb_unregister(&dev->dvb); | 911 | videobuf_dvb_unregister(&dev->dvb); |
@@ -878,33 +914,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) | |||
878 | vp3054_i2c_remove(dev); | 914 | vp3054_i2c_remove(dev); |
879 | #endif | 915 | #endif |
880 | 916 | ||
881 | /* common */ | 917 | return 0; |
882 | cx8802_fini_common(dev); | ||
883 | cx88_core_put(dev->core,dev->pci); | ||
884 | kfree(dev); | ||
885 | } | 918 | } |
886 | 919 | ||
887 | static struct pci_device_id cx8802_pci_tbl[] = { | 920 | static struct cx8802_driver cx8802_dvb_driver = { |
888 | { | 921 | .type_id = CX88_MPEG_DVB, |
889 | .vendor = 0x14f1, | 922 | .hw_access = CX8802_DRVCTL_SHARED, |
890 | .device = 0x8802, | 923 | .probe = cx8802_dvb_probe, |
891 | .subvendor = PCI_ANY_ID, | 924 | .remove = cx8802_dvb_remove, |
892 | .subdevice = PCI_ANY_ID, | 925 | .advise_acquire = cx8802_dvb_advise_acquire, |
893 | },{ | 926 | .advise_release = cx8802_dvb_advise_release, |
894 | /* --- end of list --- */ | ||
895 | } | ||
896 | }; | ||
897 | MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); | ||
898 | |||
899 | static struct pci_driver dvb_pci_driver = { | ||
900 | .name = "cx88-dvb", | ||
901 | .id_table = cx8802_pci_tbl, | ||
902 | .probe = dvb_probe, | ||
903 | .remove = __devexit_p(dvb_remove), | ||
904 | #ifdef CONFIG_PM | ||
905 | .suspend = cx8802_suspend_common, | ||
906 | .resume = cx8802_resume_common, | ||
907 | #endif | ||
908 | }; | 927 | }; |
909 | 928 | ||
910 | static int dvb_init(void) | 929 | static int dvb_init(void) |
@@ -917,12 +936,12 @@ static int dvb_init(void) | |||
917 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 936 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
918 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 937 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
919 | #endif | 938 | #endif |
920 | return pci_register_driver(&dvb_pci_driver); | 939 | return cx8802_register_driver(&cx8802_dvb_driver); |
921 | } | 940 | } |
922 | 941 | ||
923 | static void dvb_fini(void) | 942 | static void dvb_fini(void) |
924 | { | 943 | { |
925 | pci_unregister_driver(&dvb_pci_driver); | 944 | cx8802_unregister_driver(&cx8802_dvb_driver); |
926 | } | 945 | } |
927 | 946 | ||
928 | module_init(dvb_init); | 947 | module_init(dvb_init); |
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6b23a4e6f66d..6f155713ee02 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c | |||
@@ -44,8 +44,12 @@ module_param(debug,int,0644); | |||
44 | MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); | 44 | MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); |
45 | 45 | ||
46 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | 46 | #define dprintk(level,fmt, arg...) if (debug >= level) \ |
47 | printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg) | 47 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) |
48 | 48 | ||
49 | #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ | ||
50 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) | ||
51 | |||
52 | static LIST_HEAD(cx8802_devlist); | ||
49 | /* ------------------------------------------------------------------ */ | 53 | /* ------------------------------------------------------------------ */ |
50 | 54 | ||
51 | static int cx8802_start_dma(struct cx8802_dev *dev, | 55 | static int cx8802_start_dma(struct cx8802_dev *dev, |
@@ -65,17 +69,13 @@ static int cx8802_start_dma(struct cx8802_dev *dev, | |||
65 | 69 | ||
66 | /* FIXME: this needs a review. | 70 | /* FIXME: this needs a review. |
67 | * also: move to cx88-blackbird + cx88-dvb source files? */ | 71 | * also: move to cx88-blackbird + cx88-dvb source files? */ |
68 | if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) { | ||
69 | /* Report a warning until the mini driver patch is applied, | ||
70 | * else the following conditions will set the dma registers incorrectly. | ||
71 | * This will be removed in the next major patch and changes to the conditions | ||
72 | * will be made. | ||
73 | */ | ||
74 | printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | 72 | ||
78 | if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) { | 73 | dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); |
74 | |||
75 | if ( (core->active_type_id == CX88_MPEG_DVB) && | ||
76 | (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { | ||
77 | |||
78 | dprintk( 1, "cx8802_start_dma doing .dvb\n"); | ||
79 | /* negedge driven & software reset */ | 79 | /* negedge driven & software reset */ |
80 | cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); | 80 | cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); |
81 | udelay(100); | 81 | udelay(100); |
@@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev, | |||
93 | cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ | 93 | cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ |
94 | udelay(100); | 94 | udelay(100); |
95 | break; | 95 | break; |
96 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
97 | break; | ||
96 | default: | 98 | default: |
97 | cx_write(TS_SOP_STAT, 0x00); | 99 | cx_write(TS_SOP_STAT, 0x00); |
98 | break; | 100 | break; |
99 | } | 101 | } |
100 | cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); | 102 | cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); |
101 | udelay(100); | 103 | udelay(100); |
102 | } | 104 | } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && |
103 | 105 | (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { | |
104 | if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { | 106 | dprintk( 1, "cx8802_start_dma doing .blackbird\n"); |
105 | cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ | 107 | cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ |
106 | 108 | ||
107 | cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ | 109 | cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ |
@@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, | |||
112 | 114 | ||
113 | cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ | 115 | cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ |
114 | udelay(100); | 116 | udelay(100); |
117 | } else { | ||
118 | printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, | ||
119 | cx88_boards[core->board].mpeg ); | ||
120 | return -EINVAL; | ||
115 | } | 121 | } |
116 | 122 | ||
117 | /* reset counter */ | 123 | /* reset counter */ |
@@ -542,8 +548,311 @@ int cx8802_resume_common(struct pci_dev *pci_dev) | |||
542 | return 0; | 548 | return 0; |
543 | } | 549 | } |
544 | 550 | ||
551 | struct cx8802_dev * cx8802_get_device(struct inode *inode) | ||
552 | { | ||
553 | int minor = iminor(inode); | ||
554 | struct cx8802_dev *h = NULL; | ||
555 | struct list_head *list; | ||
556 | |||
557 | list_for_each(list,&cx8802_devlist) { | ||
558 | h = list_entry(list, struct cx8802_dev, devlist); | ||
559 | if (h->mpeg_dev->minor == minor) | ||
560 | return h; | ||
561 | } | ||
562 | |||
563 | return NULL; | ||
564 | } | ||
565 | |||
566 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) | ||
567 | { | ||
568 | struct cx8802_dev *h = NULL; | ||
569 | struct cx8802_driver *d = NULL; | ||
570 | struct list_head *list; | ||
571 | struct list_head *list2; | ||
572 | |||
573 | list_for_each(list,&cx8802_devlist) { | ||
574 | h = list_entry(list, struct cx8802_dev, devlist); | ||
575 | |||
576 | list_for_each(list2, &h->drvlist.devlist) { | ||
577 | d = list_entry(list2, struct cx8802_driver, devlist); | ||
578 | |||
579 | /* only unregister the correct driver type */ | ||
580 | if (d->type_id == btype) { | ||
581 | return d; | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | return NULL; | ||
587 | } | ||
588 | |||
589 | /* Driver asked for hardware access. */ | ||
590 | int cx8802_request_acquire(struct cx8802_driver *drv) | ||
591 | { | ||
592 | struct cx88_core *core = drv->core; | ||
593 | |||
594 | /* Fail a request for hardware if the device is busy. */ | ||
595 | if (core->active_type_id != CX88_BOARD_NONE) | ||
596 | return -EBUSY; | ||
597 | |||
598 | if (drv->advise_acquire) | ||
599 | { | ||
600 | core->active_type_id = drv->type_id; | ||
601 | drv->advise_acquire(drv); | ||
602 | |||
603 | mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); | ||
604 | } | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | /* Driver asked to release hardware. */ | ||
610 | int cx8802_request_release(struct cx8802_driver *drv) | ||
611 | { | ||
612 | struct cx88_core *core = drv->core; | ||
613 | |||
614 | if (drv->advise_release) | ||
615 | { | ||
616 | drv->advise_release(drv); | ||
617 | core->active_type_id = CX88_BOARD_NONE; | ||
618 | mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); | ||
619 | } | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int cx8802_check_driver(struct cx8802_driver *drv) | ||
625 | { | ||
626 | if (drv == NULL) | ||
627 | return -ENODEV; | ||
628 | |||
629 | if ((drv->type_id != CX88_MPEG_DVB) && | ||
630 | (drv->type_id != CX88_MPEG_BLACKBIRD)) | ||
631 | return -EINVAL; | ||
632 | |||
633 | if ((drv->hw_access != CX8802_DRVCTL_SHARED) && | ||
634 | (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) | ||
635 | return -EINVAL; | ||
636 | |||
637 | if ((drv->probe == NULL) || | ||
638 | (drv->remove == NULL) || | ||
639 | (drv->advise_acquire == NULL) || | ||
640 | (drv->advise_release == NULL)) | ||
641 | return -EINVAL; | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | int cx8802_register_driver(struct cx8802_driver *drv) | ||
647 | { | ||
648 | struct cx8802_dev *h; | ||
649 | struct cx8802_driver *driver; | ||
650 | struct list_head *list; | ||
651 | int err = 0, i = 0; | ||
652 | |||
653 | printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , | ||
654 | drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", | ||
655 | drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); | ||
656 | |||
657 | if ((err = cx8802_check_driver(drv)) != 0) { | ||
658 | printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); | ||
659 | return err; | ||
660 | } | ||
661 | |||
662 | list_for_each(list,&cx8802_devlist) { | ||
663 | i++; | ||
664 | h = list_entry(list, struct cx8802_dev, devlist); | ||
665 | |||
666 | printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", | ||
667 | h->core->name,h->pci->subsystem_vendor, | ||
668 | h->pci->subsystem_device,cx88_boards[h->core->board].name, | ||
669 | h->core->board); | ||
670 | |||
671 | /* Bring up a new struct for each driver instance */ | ||
672 | driver = kzalloc(sizeof(*drv),GFP_KERNEL); | ||
673 | if (driver == NULL) | ||
674 | return -ENOMEM; | ||
675 | |||
676 | /* Snapshot of the driver registration data */ | ||
677 | drv->core = h->core; | ||
678 | drv->suspend = cx8802_suspend_common; | ||
679 | drv->resume = cx8802_resume_common; | ||
680 | drv->request_acquire = cx8802_request_acquire; | ||
681 | drv->request_release = cx8802_request_release; | ||
682 | memcpy(driver, drv, sizeof(*driver)); | ||
683 | |||
684 | err = drv->probe(driver); | ||
685 | if (err == 0) { | ||
686 | mutex_lock(&drv->core->lock); | ||
687 | list_add_tail(&driver->devlist,&h->drvlist.devlist); | ||
688 | mutex_unlock(&drv->core->lock); | ||
689 | } else { | ||
690 | printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); | ||
691 | } | ||
692 | |||
693 | } | ||
694 | if (i == 0) | ||
695 | err = -ENODEV; | ||
696 | |||
697 | return err; | ||
698 | } | ||
699 | |||
700 | int cx8802_unregister_driver(struct cx8802_driver *drv) | ||
701 | { | ||
702 | struct cx8802_dev *h; | ||
703 | struct cx8802_driver *d; | ||
704 | struct list_head *list; | ||
705 | struct list_head *list2, *q; | ||
706 | int err = 0, i = 0; | ||
707 | |||
708 | printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , | ||
709 | drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); | ||
710 | |||
711 | list_for_each(list,&cx8802_devlist) { | ||
712 | i++; | ||
713 | h = list_entry(list, struct cx8802_dev, devlist); | ||
714 | |||
715 | printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", | ||
716 | h->core->name,h->pci->subsystem_vendor, | ||
717 | h->pci->subsystem_device,cx88_boards[h->core->board].name, | ||
718 | h->core->board); | ||
719 | |||
720 | list_for_each_safe(list2, q, &h->drvlist.devlist) { | ||
721 | d = list_entry(list2, struct cx8802_driver, devlist); | ||
722 | |||
723 | /* only unregister the correct driver type */ | ||
724 | if (d->type_id != drv->type_id) | ||
725 | continue; | ||
726 | |||
727 | err = d->remove(d); | ||
728 | if (err == 0) { | ||
729 | mutex_lock(&drv->core->lock); | ||
730 | list_del(list2); | ||
731 | mutex_unlock(&drv->core->lock); | ||
732 | } else | ||
733 | printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); | ||
734 | |||
735 | } | ||
736 | |||
737 | } | ||
738 | |||
739 | return err; | ||
740 | } | ||
741 | |||
545 | /* ----------------------------------------------------------- */ | 742 | /* ----------------------------------------------------------- */ |
743 | static int __devinit cx8802_probe(struct pci_dev *pci_dev, | ||
744 | const struct pci_device_id *pci_id) | ||
745 | { | ||
746 | struct cx8802_dev *dev; | ||
747 | struct cx88_core *core; | ||
748 | int err; | ||
749 | |||
750 | /* general setup */ | ||
751 | core = cx88_core_get(pci_dev); | ||
752 | if (NULL == core) | ||
753 | return -EINVAL; | ||
754 | |||
755 | printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); | ||
756 | |||
757 | err = -ENODEV; | ||
758 | if (!cx88_boards[core->board].mpeg) | ||
759 | goto fail_core; | ||
760 | |||
761 | err = -ENOMEM; | ||
762 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | ||
763 | if (NULL == dev) | ||
764 | goto fail_core; | ||
765 | dev->pci = pci_dev; | ||
766 | dev->core = core; | ||
767 | |||
768 | err = cx8802_init_common(dev); | ||
769 | if (err != 0) | ||
770 | goto fail_free; | ||
771 | |||
772 | INIT_LIST_HEAD(&dev->drvlist.devlist); | ||
773 | list_add_tail(&dev->devlist,&cx8802_devlist); | ||
546 | 774 | ||
775 | /* Maintain a reference so cx88-video can query the 8802 device. */ | ||
776 | core->dvbdev = dev; | ||
777 | return 0; | ||
778 | |||
779 | fail_free: | ||
780 | kfree(dev); | ||
781 | fail_core: | ||
782 | cx88_core_put(core,pci_dev); | ||
783 | return err; | ||
784 | } | ||
785 | |||
786 | static void __devexit cx8802_remove(struct pci_dev *pci_dev) | ||
787 | { | ||
788 | struct cx8802_dev *dev; | ||
789 | struct cx8802_driver *h; | ||
790 | struct list_head *list; | ||
791 | |||
792 | dev = pci_get_drvdata(pci_dev); | ||
793 | |||
794 | dprintk( 1, "%s\n", __FUNCTION__); | ||
795 | |||
796 | list_for_each(list,&dev->drvlist.devlist) { | ||
797 | h = list_entry(list, struct cx8802_driver, devlist); | ||
798 | dprintk( 1, " ->driver\n"); | ||
799 | if (h->remove == NULL) { | ||
800 | printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__); | ||
801 | continue; | ||
802 | } | ||
803 | printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id); | ||
804 | cx8802_unregister_driver(h); | ||
805 | list_del(&dev->drvlist.devlist); | ||
806 | } | ||
807 | |||
808 | /* Destroy any 8802 reference. */ | ||
809 | dev->core->dvbdev = NULL; | ||
810 | |||
811 | /* common */ | ||
812 | cx8802_fini_common(dev); | ||
813 | cx88_core_put(dev->core,dev->pci); | ||
814 | kfree(dev); | ||
815 | } | ||
816 | |||
817 | static struct pci_device_id cx8802_pci_tbl[] = { | ||
818 | { | ||
819 | .vendor = 0x14f1, | ||
820 | .device = 0x8802, | ||
821 | .subvendor = PCI_ANY_ID, | ||
822 | .subdevice = PCI_ANY_ID, | ||
823 | },{ | ||
824 | /* --- end of list --- */ | ||
825 | } | ||
826 | }; | ||
827 | MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); | ||
828 | |||
829 | static struct pci_driver cx8802_pci_driver = { | ||
830 | .name = "cx88-mpeg driver manager", | ||
831 | .id_table = cx8802_pci_tbl, | ||
832 | .probe = cx8802_probe, | ||
833 | .remove = __devexit_p(cx8802_remove), | ||
834 | }; | ||
835 | |||
836 | static int cx8802_init(void) | ||
837 | { | ||
838 | printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", | ||
839 | (CX88_VERSION_CODE >> 16) & 0xff, | ||
840 | (CX88_VERSION_CODE >> 8) & 0xff, | ||
841 | CX88_VERSION_CODE & 0xff); | ||
842 | #ifdef SNAPSHOT | ||
843 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | ||
844 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | ||
845 | #endif | ||
846 | return pci_register_driver(&cx8802_pci_driver); | ||
847 | } | ||
848 | |||
849 | static void cx8802_fini(void) | ||
850 | { | ||
851 | pci_unregister_driver(&cx8802_pci_driver); | ||
852 | } | ||
853 | |||
854 | module_init(cx8802_init); | ||
855 | module_exit(cx8802_fini); | ||
547 | EXPORT_SYMBOL(cx8802_buf_prepare); | 856 | EXPORT_SYMBOL(cx8802_buf_prepare); |
548 | EXPORT_SYMBOL(cx8802_buf_queue); | 857 | EXPORT_SYMBOL(cx8802_buf_queue); |
549 | EXPORT_SYMBOL(cx8802_cancel_buffers); | 858 | EXPORT_SYMBOL(cx8802_cancel_buffers); |
@@ -551,9 +860,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers); | |||
551 | EXPORT_SYMBOL(cx8802_init_common); | 860 | EXPORT_SYMBOL(cx8802_init_common); |
552 | EXPORT_SYMBOL(cx8802_fini_common); | 861 | EXPORT_SYMBOL(cx8802_fini_common); |
553 | 862 | ||
554 | EXPORT_SYMBOL(cx8802_suspend_common); | 863 | EXPORT_SYMBOL(cx8802_register_driver); |
555 | EXPORT_SYMBOL(cx8802_resume_common); | 864 | EXPORT_SYMBOL(cx8802_unregister_driver); |
556 | 865 | EXPORT_SYMBOL(cx8802_get_device); | |
866 | EXPORT_SYMBOL(cx8802_get_driver); | ||
557 | /* ----------------------------------------------------------- */ | 867 | /* ----------------------------------------------------------- */ |
558 | /* | 868 | /* |
559 | * Local variables: | 869 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3bc91aad4fe5..5980e47aee13 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -74,6 +74,11 @@ enum cx88_board_type { | |||
74 | CX88_MPEG_BLACKBIRD | 74 | CX88_MPEG_BLACKBIRD |
75 | }; | 75 | }; |
76 | 76 | ||
77 | enum cx8802_board_access { | ||
78 | CX8802_DRVCTL_SHARED = 1, | ||
79 | CX8802_DRVCTL_EXCLUSIVE = 2, | ||
80 | }; | ||
81 | |||
77 | /* ----------------------------------------------------------- */ | 82 | /* ----------------------------------------------------------- */ |
78 | /* tv norms */ | 83 | /* tv norms */ |
79 | 84 | ||
@@ -330,6 +335,7 @@ struct cx88_core { | |||
330 | 335 | ||
331 | /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ | 336 | /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ |
332 | struct cx8802_dev *dvbdev; | 337 | struct cx8802_dev *dvbdev; |
338 | enum cx88_board_type active_type_id; | ||
333 | }; | 339 | }; |
334 | 340 | ||
335 | struct cx8800_dev; | 341 | struct cx8800_dev; |
@@ -405,6 +411,31 @@ struct cx8802_suspend_state { | |||
405 | int disabled; | 411 | int disabled; |
406 | }; | 412 | }; |
407 | 413 | ||
414 | struct cx8802_driver { | ||
415 | struct cx88_core *core; | ||
416 | struct list_head devlist; | ||
417 | |||
418 | /* Type of driver and access required */ | ||
419 | enum cx88_board_type type_id; | ||
420 | enum cx8802_board_access hw_access; | ||
421 | |||
422 | /* MPEG 8802 internal only */ | ||
423 | int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); | ||
424 | int (*resume)(struct pci_dev *pci_dev); | ||
425 | |||
426 | /* MPEG 8802 -> mini driver - Driver probe and configuration */ | ||
427 | int (*probe)(struct cx8802_driver *drv); | ||
428 | int (*remove)(struct cx8802_driver *drv); | ||
429 | |||
430 | /* MPEG 8802 -> mini driver - Access for hardware control */ | ||
431 | int (*advise_acquire)(struct cx8802_driver *drv); | ||
432 | int (*advise_release)(struct cx8802_driver *drv); | ||
433 | |||
434 | /* MPEG 8802 <- mini driver - Access for hardware control */ | ||
435 | int (*request_acquire)(struct cx8802_driver *drv); | ||
436 | int (*request_release)(struct cx8802_driver *drv); | ||
437 | }; | ||
438 | |||
408 | struct cx8802_dev { | 439 | struct cx8802_dev { |
409 | struct cx88_core *core; | 440 | struct cx88_core *core; |
410 | spinlock_t slock; | 441 | spinlock_t slock; |
@@ -439,6 +470,9 @@ struct cx8802_dev { | |||
439 | 470 | ||
440 | /* mpeg params */ | 471 | /* mpeg params */ |
441 | struct cx2341x_mpeg_params params; | 472 | struct cx2341x_mpeg_params params; |
473 | |||
474 | /* List of attached drivers */ | ||
475 | struct cx8802_driver drvlist; | ||
442 | }; | 476 | }; |
443 | 477 | ||
444 | /* ----------------------------------------------------------- */ | 478 | /* ----------------------------------------------------------- */ |
@@ -571,6 +605,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); | |||
571 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); | 605 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); |
572 | int cx88_audio_thread(void *data); | 606 | int cx88_audio_thread(void *data); |
573 | 607 | ||
608 | int cx8802_register_driver(struct cx8802_driver *drv); | ||
609 | int cx8802_unregister_driver(struct cx8802_driver *drv); | ||
610 | struct cx8802_dev * cx8802_get_device(struct inode *inode); | ||
611 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); | ||
612 | |||
574 | /* ----------------------------------------------------------- */ | 613 | /* ----------------------------------------------------------- */ |
575 | /* cx88-input.c */ | 614 | /* cx88-input.c */ |
576 | 615 | ||
@@ -600,6 +639,13 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, | |||
600 | extern const u32 cx88_user_ctrls[]; | 639 | extern const u32 cx88_user_ctrls[]; |
601 | extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl); | 640 | extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl); |
602 | 641 | ||
642 | /* ----------------------------------------------------------- */ | ||
643 | /* cx88-blackbird.c */ | ||
644 | /* used by cx88-ivtv ioctl emulation layer */ | ||
645 | extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
646 | unsigned int cmd, void *arg); | ||
647 | extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
648 | |||
603 | /* | 649 | /* |
604 | * Local variables: | 650 | * Local variables: |
605 | * c-basic-offset: 8 | 651 | * c-basic-offset: 8 |