brintos

brintos / linux-shallow public Read only

0
0
Text · 9.4 KiB · 73c95ba Raw
410 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>5 */6 7#include "pvrusb2-context.h"8#include "pvrusb2-io.h"9#include "pvrusb2-ioread.h"10#include "pvrusb2-hdw.h"11#include "pvrusb2-debug.h"12#include <linux/wait.h>13#include <linux/kthread.h>14#include <linux/errno.h>15#include <linux/string.h>16#include <linux/slab.h>17 18static struct pvr2_context *pvr2_context_exist_first;19static struct pvr2_context *pvr2_context_exist_last;20static struct pvr2_context *pvr2_context_notify_first;21static struct pvr2_context *pvr2_context_notify_last;22static DEFINE_MUTEX(pvr2_context_mutex);23static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);24static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);25static int pvr2_context_cleanup_flag;26static int pvr2_context_cleaned_flag;27static struct task_struct *pvr2_context_thread_ptr;28 29 30static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)31{32	int signal_flag = 0;33	mutex_lock(&pvr2_context_mutex);34	if (fl) {35		if (!mp->notify_flag) {36			signal_flag = (pvr2_context_notify_first == NULL);37			mp->notify_prev = pvr2_context_notify_last;38			mp->notify_next = NULL;39			pvr2_context_notify_last = mp;40			if (mp->notify_prev) {41				mp->notify_prev->notify_next = mp;42			} else {43				pvr2_context_notify_first = mp;44			}45			mp->notify_flag = !0;46		}47	} else {48		if (mp->notify_flag) {49			mp->notify_flag = 0;50			if (mp->notify_next) {51				mp->notify_next->notify_prev = mp->notify_prev;52			} else {53				pvr2_context_notify_last = mp->notify_prev;54			}55			if (mp->notify_prev) {56				mp->notify_prev->notify_next = mp->notify_next;57			} else {58				pvr2_context_notify_first = mp->notify_next;59			}60		}61	}62	mutex_unlock(&pvr2_context_mutex);63	if (signal_flag) wake_up(&pvr2_context_sync_data);64}65 66 67static void pvr2_context_destroy(struct pvr2_context *mp)68{69	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);70	pvr2_hdw_destroy(mp->hdw);71	pvr2_context_set_notify(mp, 0);72	mutex_lock(&pvr2_context_mutex);73	if (mp->exist_next) {74		mp->exist_next->exist_prev = mp->exist_prev;75	} else {76		pvr2_context_exist_last = mp->exist_prev;77	}78	if (mp->exist_prev) {79		mp->exist_prev->exist_next = mp->exist_next;80	} else {81		pvr2_context_exist_first = mp->exist_next;82	}83	if (!pvr2_context_exist_first) {84		/* Trigger wakeup on control thread in case it is waiting85		   for an exit condition. */86		wake_up(&pvr2_context_sync_data);87	}88	mutex_unlock(&pvr2_context_mutex);89	kfree(mp);90}91 92 93static void pvr2_context_notify(void *ptr)94{95	struct pvr2_context *mp = ptr;96 97	pvr2_context_set_notify(mp,!0);98}99 100 101static void pvr2_context_check(struct pvr2_context *mp)102{103	struct pvr2_channel *ch1, *ch2;104	pvr2_trace(PVR2_TRACE_CTXT,105		   "pvr2_context %p (notify)", mp);106	if (!mp->initialized_flag && !mp->disconnect_flag) {107		mp->initialized_flag = !0;108		pvr2_trace(PVR2_TRACE_CTXT,109			   "pvr2_context %p (initialize)", mp);110		/* Finish hardware initialization */111		if (pvr2_hdw_initialize(mp->hdw, pvr2_context_notify, mp)) {112			mp->video_stream.stream =113				pvr2_hdw_get_video_stream(mp->hdw);114			/* Trigger interface initialization.  By doing this115			   here initialization runs in our own safe and116			   cozy thread context. */117			if (mp->setup_func) mp->setup_func(mp);118		} else {119			pvr2_trace(PVR2_TRACE_CTXT,120				   "pvr2_context %p (thread skipping setup)",121				   mp);122			/* Even though initialization did not succeed,123			   we're still going to continue anyway.  We need124			   to do this in order to await the expected125			   disconnect (which we will detect in the normal126			   course of operation). */127		}128	}129 130	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {131		ch2 = ch1->mc_next;132		if (ch1->check_func) ch1->check_func(ch1);133	}134 135	if (mp->disconnect_flag && !mp->mc_first) {136		/* Go away... */137		pvr2_context_destroy(mp);138		return;139	}140}141 142 143static int pvr2_context_shutok(void)144{145	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);146}147 148 149static int pvr2_context_thread_func(void *foo)150{151	struct pvr2_context *mp;152 153	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");154 155	do {156		while ((mp = pvr2_context_notify_first) != NULL) {157			pvr2_context_set_notify(mp, 0);158			pvr2_context_check(mp);159		}160		wait_event_interruptible(161			pvr2_context_sync_data,162			((pvr2_context_notify_first != NULL) ||163			 pvr2_context_shutok()));164	} while (!pvr2_context_shutok());165 166	pvr2_context_cleaned_flag = !0;167	wake_up(&pvr2_context_cleanup_data);168 169	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");170 171	wait_event_interruptible(172		pvr2_context_sync_data,173		kthread_should_stop());174 175	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");176 177	return 0;178}179 180 181int pvr2_context_global_init(void)182{183	pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,184					      NULL,185					      "pvrusb2-context");186	return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;187}188 189 190void pvr2_context_global_done(void)191{192	pvr2_context_cleanup_flag = !0;193	wake_up(&pvr2_context_sync_data);194	wait_event_interruptible(195		pvr2_context_cleanup_data,196		pvr2_context_cleaned_flag);197	kthread_stop(pvr2_context_thread_ptr);198}199 200 201struct pvr2_context *pvr2_context_create(202	struct usb_interface *intf,203	const struct usb_device_id *devid,204	void (*setup_func)(struct pvr2_context *))205{206	struct pvr2_context *mp = NULL;207	mp = kzalloc(sizeof(*mp),GFP_KERNEL);208	if (!mp) goto done;209	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);210	mp->setup_func = setup_func;211	mutex_init(&mp->mutex);212	mutex_lock(&pvr2_context_mutex);213	mp->exist_prev = pvr2_context_exist_last;214	mp->exist_next = NULL;215	pvr2_context_exist_last = mp;216	if (mp->exist_prev) {217		mp->exist_prev->exist_next = mp;218	} else {219		pvr2_context_exist_first = mp;220	}221	mutex_unlock(&pvr2_context_mutex);222	mp->hdw = pvr2_hdw_create(intf,devid);223	if (!mp->hdw) {224		pvr2_context_destroy(mp);225		mp = NULL;226		goto done;227	}228	pvr2_context_set_notify(mp, !0);229 done:230	return mp;231}232 233 234static void pvr2_context_reset_input_limits(struct pvr2_context *mp)235{236	unsigned int tmsk,mmsk;237	struct pvr2_channel *cp;238	struct pvr2_hdw *hdw = mp->hdw;239	mmsk = pvr2_hdw_get_input_available(hdw);240	tmsk = mmsk;241	for (cp = mp->mc_first; cp; cp = cp->mc_next) {242		if (!cp->input_mask) continue;243		tmsk &= cp->input_mask;244	}245	pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);246	pvr2_hdw_commit_ctl(hdw);247}248 249 250static void pvr2_context_enter(struct pvr2_context *mp)251{252	mutex_lock(&mp->mutex);253}254 255 256static void pvr2_context_exit(struct pvr2_context *mp)257{258	int destroy_flag = 0;259	if (!(mp->mc_first || !mp->disconnect_flag)) {260		destroy_flag = !0;261	}262	mutex_unlock(&mp->mutex);263	if (destroy_flag) pvr2_context_notify(mp);264}265 266 267void pvr2_context_disconnect(struct pvr2_context *mp)268{269	pvr2_hdw_disconnect(mp->hdw);270	if (!pvr2_context_shutok())271		pvr2_context_notify(mp);272	mp->disconnect_flag = !0;273}274 275 276void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)277{278	pvr2_context_enter(mp);279	cp->hdw = mp->hdw;280	cp->mc_head = mp;281	cp->mc_next = NULL;282	cp->mc_prev = mp->mc_last;283	if (mp->mc_last) {284		mp->mc_last->mc_next = cp;285	} else {286		mp->mc_first = cp;287	}288	mp->mc_last = cp;289	pvr2_context_exit(mp);290}291 292 293static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)294{295	if (!cp->stream) return;296	pvr2_stream_kill(cp->stream->stream);297	cp->stream->user = NULL;298	cp->stream = NULL;299}300 301 302void pvr2_channel_done(struct pvr2_channel *cp)303{304	struct pvr2_context *mp = cp->mc_head;305	pvr2_context_enter(mp);306	cp->input_mask = 0;307	pvr2_channel_disclaim_stream(cp);308	pvr2_context_reset_input_limits(mp);309	if (cp->mc_next) {310		cp->mc_next->mc_prev = cp->mc_prev;311	} else {312		mp->mc_last = cp->mc_prev;313	}314	if (cp->mc_prev) {315		cp->mc_prev->mc_next = cp->mc_next;316	} else {317		mp->mc_first = cp->mc_next;318	}319	cp->hdw = NULL;320	pvr2_context_exit(mp);321}322 323 324int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)325{326	unsigned int tmsk,mmsk;327	int ret = 0;328	struct pvr2_channel *p2;329	struct pvr2_hdw *hdw = cp->hdw;330 331	mmsk = pvr2_hdw_get_input_available(hdw);332	cmsk &= mmsk;333	if (cmsk == cp->input_mask) {334		/* No change; nothing to do */335		return 0;336	}337 338	pvr2_context_enter(cp->mc_head);339	do {340		if (!cmsk) {341			cp->input_mask = 0;342			pvr2_context_reset_input_limits(cp->mc_head);343			break;344		}345		tmsk = mmsk;346		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {347			if (p2 == cp) continue;348			if (!p2->input_mask) continue;349			tmsk &= p2->input_mask;350		}351		if (!(tmsk & cmsk)) {352			ret = -EPERM;353			break;354		}355		tmsk &= cmsk;356		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {357			/* Internal failure changing allowed list; probably358			   should not happen, but react if it does. */359			break;360		}361		cp->input_mask = cmsk;362		pvr2_hdw_commit_ctl(hdw);363	} while (0);364	pvr2_context_exit(cp->mc_head);365	return ret;366}367 368 369unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)370{371	return cp->input_mask;372}373 374 375int pvr2_channel_claim_stream(struct pvr2_channel *cp,376			      struct pvr2_context_stream *sp)377{378	int code = 0;379	pvr2_context_enter(cp->mc_head); do {380		if (sp == cp->stream) break;381		if (sp && sp->user) {382			code = -EBUSY;383			break;384		}385		pvr2_channel_disclaim_stream(cp);386		if (!sp) break;387		sp->user = cp;388		cp->stream = sp;389	} while (0);390	pvr2_context_exit(cp->mc_head);391	return code;392}393 394 395// This is the marker for the real beginning of a legitimate mpeg2 stream.396static char stream_sync_key[] = {397	0x00, 0x00, 0x01, 0xba,398};399 400struct pvr2_ioread *pvr2_channel_create_mpeg_stream(401	struct pvr2_context_stream *sp)402{403	struct pvr2_ioread *cp;404	cp = pvr2_ioread_create();405	if (!cp) return NULL;406	pvr2_ioread_setup(cp,sp->stream);407	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));408	return cp;409}410