cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pvrusb2-context.c (9623B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      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 waiting
     85		   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(struct pvr2_context *mp)
     94{
     95	pvr2_context_set_notify(mp,!0);
     96}
     97
     98
     99static void pvr2_context_check(struct pvr2_context *mp)
    100{
    101	struct pvr2_channel *ch1, *ch2;
    102	pvr2_trace(PVR2_TRACE_CTXT,
    103		   "pvr2_context %p (notify)", mp);
    104	if (!mp->initialized_flag && !mp->disconnect_flag) {
    105		mp->initialized_flag = !0;
    106		pvr2_trace(PVR2_TRACE_CTXT,
    107			   "pvr2_context %p (initialize)", mp);
    108		/* Finish hardware initialization */
    109		if (pvr2_hdw_initialize(mp->hdw,
    110					(void (*)(void *))pvr2_context_notify,
    111					mp)) {
    112			mp->video_stream.stream =
    113				pvr2_hdw_get_video_stream(mp->hdw);
    114			/* Trigger interface initialization.  By doing this
    115			   here initialization runs in our own safe and
    116			   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 need
    124			   to do this in order to await the expected
    125			   disconnect (which we will detect in the normal
    126			   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	mp->disconnect_flag = !0;
    271	pvr2_context_notify(mp);
    272}
    273
    274
    275void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
    276{
    277	pvr2_context_enter(mp);
    278	cp->hdw = mp->hdw;
    279	cp->mc_head = mp;
    280	cp->mc_next = NULL;
    281	cp->mc_prev = mp->mc_last;
    282	if (mp->mc_last) {
    283		mp->mc_last->mc_next = cp;
    284	} else {
    285		mp->mc_first = cp;
    286	}
    287	mp->mc_last = cp;
    288	pvr2_context_exit(mp);
    289}
    290
    291
    292static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
    293{
    294	if (!cp->stream) return;
    295	pvr2_stream_kill(cp->stream->stream);
    296	cp->stream->user = NULL;
    297	cp->stream = NULL;
    298}
    299
    300
    301void pvr2_channel_done(struct pvr2_channel *cp)
    302{
    303	struct pvr2_context *mp = cp->mc_head;
    304	pvr2_context_enter(mp);
    305	cp->input_mask = 0;
    306	pvr2_channel_disclaim_stream(cp);
    307	pvr2_context_reset_input_limits(mp);
    308	if (cp->mc_next) {
    309		cp->mc_next->mc_prev = cp->mc_prev;
    310	} else {
    311		mp->mc_last = cp->mc_prev;
    312	}
    313	if (cp->mc_prev) {
    314		cp->mc_prev->mc_next = cp->mc_next;
    315	} else {
    316		mp->mc_first = cp->mc_next;
    317	}
    318	cp->hdw = NULL;
    319	pvr2_context_exit(mp);
    320}
    321
    322
    323int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
    324{
    325	unsigned int tmsk,mmsk;
    326	int ret = 0;
    327	struct pvr2_channel *p2;
    328	struct pvr2_hdw *hdw = cp->hdw;
    329
    330	mmsk = pvr2_hdw_get_input_available(hdw);
    331	cmsk &= mmsk;
    332	if (cmsk == cp->input_mask) {
    333		/* No change; nothing to do */
    334		return 0;
    335	}
    336
    337	pvr2_context_enter(cp->mc_head);
    338	do {
    339		if (!cmsk) {
    340			cp->input_mask = 0;
    341			pvr2_context_reset_input_limits(cp->mc_head);
    342			break;
    343		}
    344		tmsk = mmsk;
    345		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
    346			if (p2 == cp) continue;
    347			if (!p2->input_mask) continue;
    348			tmsk &= p2->input_mask;
    349		}
    350		if (!(tmsk & cmsk)) {
    351			ret = -EPERM;
    352			break;
    353		}
    354		tmsk &= cmsk;
    355		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
    356			/* Internal failure changing allowed list; probably
    357			   should not happen, but react if it does. */
    358			break;
    359		}
    360		cp->input_mask = cmsk;
    361		pvr2_hdw_commit_ctl(hdw);
    362	} while (0);
    363	pvr2_context_exit(cp->mc_head);
    364	return ret;
    365}
    366
    367
    368unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
    369{
    370	return cp->input_mask;
    371}
    372
    373
    374int pvr2_channel_claim_stream(struct pvr2_channel *cp,
    375			      struct pvr2_context_stream *sp)
    376{
    377	int code = 0;
    378	pvr2_context_enter(cp->mc_head); do {
    379		if (sp == cp->stream) break;
    380		if (sp && sp->user) {
    381			code = -EBUSY;
    382			break;
    383		}
    384		pvr2_channel_disclaim_stream(cp);
    385		if (!sp) break;
    386		sp->user = cp;
    387		cp->stream = sp;
    388	} while (0);
    389	pvr2_context_exit(cp->mc_head);
    390	return code;
    391}
    392
    393
    394// This is the marker for the real beginning of a legitimate mpeg2 stream.
    395static char stream_sync_key[] = {
    396	0x00, 0x00, 0x01, 0xba,
    397};
    398
    399struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
    400	struct pvr2_context_stream *sp)
    401{
    402	struct pvr2_ioread *cp;
    403	cp = pvr2_ioread_create();
    404	if (!cp) return NULL;
    405	pvr2_ioread_setup(cp,sp->stream);
    406	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
    407	return cp;
    408}