V4L/DVB (4861): Remove the need of a STD array for drivers using video_ioctl2
video_ioctl2 will auto-generate standard entries at ENUM_FMT. Also, now, a driver may return a subset of the video array at the return, to be stored as the current_norm. For example, a driver may ask for V4L2_STD_PAL. At return, driver may change it to V4L2_STD_PAL_B. This way, a futher call to G_STD will return the exact detected video std. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
207705cd7f
commit
e75f9cee32
@ -1679,24 +1679,11 @@ static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* from vivi.c */
|
/* from vivi.c */
|
||||||
static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
|
static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The TV Norm stuff is weird - we're a camera with little to do with TV,
|
|
||||||
* really. The following is what vivi does.
|
|
||||||
*/
|
|
||||||
static struct v4l2_tvnorm cafe_tvnorm[] = {
|
|
||||||
{
|
|
||||||
.name = "NTSC-M",
|
|
||||||
.id = V4L2_STD_NTSC_M,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void cafe_v4l_dev_release(struct video_device *vd)
|
static void cafe_v4l_dev_release(struct video_device *vd)
|
||||||
{
|
{
|
||||||
struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
|
struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
|
||||||
@ -1726,8 +1713,7 @@ static struct video_device cafe_v4l_template = {
|
|||||||
.type = VFL_TYPE_GRABBER,
|
.type = VFL_TYPE_GRABBER,
|
||||||
.type2 = VID_TYPE_CAPTURE,
|
.type2 = VID_TYPE_CAPTURE,
|
||||||
.minor = -1, /* Get one dynamically */
|
.minor = -1, /* Get one dynamically */
|
||||||
.tvnorms = cafe_tvnorm,
|
.tvnorms = V4L2_STD_NTSC_M,
|
||||||
.tvnormsize = 1,
|
|
||||||
.current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */
|
.current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */
|
||||||
|
|
||||||
.fops = &cafe_v4l_fops,
|
.fops = &cafe_v4l_fops,
|
||||||
|
@ -87,6 +87,78 @@ MODULE_LICENSE("GPL");
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
char *v4l2_norm_to_name(v4l2_std_id id)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case V4L2_STD_PAL:
|
||||||
|
name="PAL"; break;
|
||||||
|
case V4L2_STD_PAL_BG:
|
||||||
|
name="PAL-BG"; break;
|
||||||
|
case V4L2_STD_PAL_DK:
|
||||||
|
name="PAL-DK"; break;
|
||||||
|
case V4L2_STD_PAL_B:
|
||||||
|
name="PAL-B"; break;
|
||||||
|
case V4L2_STD_PAL_B1:
|
||||||
|
name="PAL-B1"; break;
|
||||||
|
case V4L2_STD_PAL_G:
|
||||||
|
name="PAL-G"; break;
|
||||||
|
case V4L2_STD_PAL_H:
|
||||||
|
name="PAL-H"; break;
|
||||||
|
case V4L2_STD_PAL_I:
|
||||||
|
name="PAL-I"; break;
|
||||||
|
case V4L2_STD_PAL_D:
|
||||||
|
name="PAL-D"; break;
|
||||||
|
case V4L2_STD_PAL_D1:
|
||||||
|
name="PAL-D1"; break;
|
||||||
|
case V4L2_STD_PAL_K:
|
||||||
|
name="PAL-K"; break;
|
||||||
|
case V4L2_STD_PAL_M:
|
||||||
|
name="PAL-M"; break;
|
||||||
|
case V4L2_STD_PAL_N:
|
||||||
|
name="PAL-N"; break;
|
||||||
|
case V4L2_STD_PAL_Nc:
|
||||||
|
name="PAL-Nc"; break;
|
||||||
|
case V4L2_STD_PAL_60:
|
||||||
|
name="PAL-60"; break;
|
||||||
|
case V4L2_STD_NTSC:
|
||||||
|
name="NTSC"; break;
|
||||||
|
case V4L2_STD_NTSC_M:
|
||||||
|
name="NTSC-M"; break;
|
||||||
|
case V4L2_STD_NTSC_M_JP:
|
||||||
|
name="NTSC-M-JP"; break;
|
||||||
|
case V4L2_STD_NTSC_443:
|
||||||
|
name="NTSC-443"; break;
|
||||||
|
case V4L2_STD_NTSC_M_KR:
|
||||||
|
name="NTSC-M-KR"; break;
|
||||||
|
case V4L2_STD_SECAM:
|
||||||
|
name="SECAM"; break;
|
||||||
|
case V4L2_STD_SECAM_DK:
|
||||||
|
name="SECAM-DK"; break;
|
||||||
|
case V4L2_STD_SECAM_B:
|
||||||
|
name="SECAM-B"; break;
|
||||||
|
case V4L2_STD_SECAM_D:
|
||||||
|
name="SECAM-D"; break;
|
||||||
|
case V4L2_STD_SECAM_G:
|
||||||
|
name="SECAM-G"; break;
|
||||||
|
case V4L2_STD_SECAM_H:
|
||||||
|
name="SECAM-H"; break;
|
||||||
|
case V4L2_STD_SECAM_K:
|
||||||
|
name="SECAM-K"; break;
|
||||||
|
case V4L2_STD_SECAM_K1:
|
||||||
|
name="SECAM-K1"; break;
|
||||||
|
case V4L2_STD_SECAM_L:
|
||||||
|
name="SECAM-L"; break;
|
||||||
|
case V4L2_STD_SECAM_LC:
|
||||||
|
name="SECAM-LC"; break;
|
||||||
|
default:
|
||||||
|
name="Unknown"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill in the fields of a v4l2_standard structure according to the
|
/* Fill in the fields of a v4l2_standard structure according to the
|
||||||
'id' and 'transmission' parameters. Returns negative on error. */
|
'id' and 'transmission' parameters. Returns negative on error. */
|
||||||
int v4l2_video_std_construct(struct v4l2_standard *vs,
|
int v4l2_video_std_construct(struct v4l2_standard *vs,
|
||||||
@ -1453,6 +1525,7 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(v4l2_norm_to_name);
|
||||||
EXPORT_SYMBOL(v4l2_video_std_construct);
|
EXPORT_SYMBOL(v4l2_video_std_construct);
|
||||||
|
|
||||||
EXPORT_SYMBOL(v4l2_prio_init);
|
EXPORT_SYMBOL(v4l2_prio_init);
|
||||||
|
@ -833,20 +833,85 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
|
|||||||
case VIDIOC_ENUMSTD:
|
case VIDIOC_ENUMSTD:
|
||||||
{
|
{
|
||||||
struct v4l2_standard *p = arg;
|
struct v4l2_standard *p = arg;
|
||||||
unsigned int index = p->index;
|
v4l2_std_id id = vfd->tvnorms,curr_id=0;
|
||||||
|
unsigned int index = p->index,i;
|
||||||
|
|
||||||
if (!vfd->tvnormsize) {
|
if (index<0) {
|
||||||
printk (KERN_WARNING "%s: no TV norms defined!\n",
|
|
||||||
vfd->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index<0 || index >= vfd->tvnormsize) {
|
|
||||||
ret=-EINVAL;
|
ret=-EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
|
|
||||||
vfd->tvnorms[p->index].name);
|
/* Return norm array on a canonical way */
|
||||||
|
for (i=0;i<= index && id; i++) {
|
||||||
|
if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
|
||||||
|
curr_id = V4L2_STD_PAL;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
|
||||||
|
curr_id = V4L2_STD_PAL_BG;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
|
||||||
|
curr_id = V4L2_STD_PAL_DK;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
|
||||||
|
curr_id = V4L2_STD_PAL_B;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
|
||||||
|
curr_id = V4L2_STD_PAL_B1;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
|
||||||
|
curr_id = V4L2_STD_PAL_G;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
|
||||||
|
curr_id = V4L2_STD_PAL_H;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
|
||||||
|
curr_id = V4L2_STD_PAL_I;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
|
||||||
|
curr_id = V4L2_STD_PAL_D;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
|
||||||
|
curr_id = V4L2_STD_PAL_D1;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
|
||||||
|
curr_id = V4L2_STD_PAL_K;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
|
||||||
|
curr_id = V4L2_STD_PAL_M;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
|
||||||
|
curr_id = V4L2_STD_PAL_N;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
|
||||||
|
curr_id = V4L2_STD_PAL_Nc;
|
||||||
|
} else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
|
||||||
|
curr_id = V4L2_STD_PAL_60;
|
||||||
|
} else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
|
||||||
|
curr_id = V4L2_STD_NTSC;
|
||||||
|
} else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
|
||||||
|
curr_id = V4L2_STD_NTSC_M;
|
||||||
|
} else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
|
||||||
|
curr_id = V4L2_STD_NTSC_M_JP;
|
||||||
|
} else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
|
||||||
|
curr_id = V4L2_STD_NTSC_443;
|
||||||
|
} else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
|
||||||
|
curr_id = V4L2_STD_NTSC_M_KR;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
|
||||||
|
curr_id = V4L2_STD_SECAM;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
|
||||||
|
curr_id = V4L2_STD_SECAM_DK;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
|
||||||
|
curr_id = V4L2_STD_SECAM_B;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
|
||||||
|
curr_id = V4L2_STD_SECAM_D;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
|
||||||
|
curr_id = V4L2_STD_SECAM_G;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
|
||||||
|
curr_id = V4L2_STD_SECAM_H;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
|
||||||
|
curr_id = V4L2_STD_SECAM_K;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
|
||||||
|
curr_id = V4L2_STD_SECAM_K1;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
|
||||||
|
curr_id = V4L2_STD_SECAM_L;
|
||||||
|
} else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
|
||||||
|
curr_id = V4L2_STD_SECAM_LC;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
id &= ~curr_id;
|
||||||
|
}
|
||||||
|
if (i<=index)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
|
||||||
p->index = index;
|
p->index = index;
|
||||||
|
|
||||||
dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
|
dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
|
||||||
@ -872,39 +937,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
|
|||||||
}
|
}
|
||||||
case VIDIOC_S_STD:
|
case VIDIOC_S_STD:
|
||||||
{
|
{
|
||||||
v4l2_std_id *id = arg;
|
v4l2_std_id *id = arg,norm;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (!vfd->tvnormsize) {
|
|
||||||
printk (KERN_WARNING "%s: no TV norms defined!\n",
|
|
||||||
vfd->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
|
dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
|
||||||
|
|
||||||
/* First search for exact match */
|
norm = (*id) & vfd->tvnorms;
|
||||||
for (i = 0; i < vfd->tvnormsize; i++)
|
if ( vfd->tvnorms && !norm) /* Check if std is supported */
|
||||||
if (*id == vfd->tvnorms[i].id)
|
|
||||||
break;
|
|
||||||
/* Then for a generic video std that contains desired std */
|
|
||||||
if (i == vfd->tvnormsize)
|
|
||||||
for (i = 0; i < vfd->tvnormsize; i++)
|
|
||||||
if (*id & vfd->tvnorms[i].id)
|
|
||||||
break;
|
|
||||||
if (i == vfd->tvnormsize) {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* Calls the specific handler */
|
/* Calls the specific handler */
|
||||||
if (vfd->vidioc_s_std)
|
if (vfd->vidioc_s_std)
|
||||||
ret=vfd->vidioc_s_std(file, fh, i);
|
ret=vfd->vidioc_s_std(file, fh, &norm);
|
||||||
else
|
else
|
||||||
ret=-EINVAL;
|
ret=-EINVAL;
|
||||||
|
|
||||||
/* Updates standard information */
|
/* Updates standard information */
|
||||||
if (!ret)
|
if (ret>=0)
|
||||||
vfd->current_norm=*id;
|
vfd->current_norm=norm;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1296,25 +1345,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
|
|||||||
ret=vfd->vidioc_g_parm(file, fh, p);
|
ret=vfd->vidioc_g_parm(file, fh, p);
|
||||||
} else {
|
} else {
|
||||||
struct v4l2_standard s;
|
struct v4l2_standard s;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!vfd->tvnormsize) {
|
|
||||||
printk (KERN_WARNING "%s: no TV norms defined!\n",
|
|
||||||
vfd->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < vfd->tvnormsize; i++)
|
|
||||||
if (vfd->tvnorms[i].id == vfd->current_norm)
|
|
||||||
break;
|
|
||||||
if (i >= vfd->tvnormsize)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
v4l2_video_std_construct(&s, vfd->current_norm,
|
v4l2_video_std_construct(&s, vfd->current_norm,
|
||||||
vfd->tvnorms[i].name);
|
v4l2_norm_to_name(vfd->current_norm));
|
||||||
|
|
||||||
memset(p,0,sizeof(*p));
|
memset(p,0,sizeof(*p));
|
||||||
|
|
||||||
|
@ -1044,16 +1044,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct v4l2_tvnorm tvnorms[] = {
|
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
|
||||||
{
|
|
||||||
.name = "NTSC-M",
|
|
||||||
.id = V4L2_STD_NTSC_M,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1333,8 +1325,8 @@ static struct video_device vivi = {
|
|||||||
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
#ifdef CONFIG_VIDEO_V4L1_COMPAT
|
||||||
.vidiocgmbuf = vidiocgmbuf,
|
.vidiocgmbuf = vidiocgmbuf,
|
||||||
#endif
|
#endif
|
||||||
.tvnorms = tvnorms,
|
.tvnorms = V4L2_STD_NTSC_M,
|
||||||
.tvnormsize = ARRAY_SIZE(tvnorms),
|
.current_norm = V4L2_STD_NTSC_M,
|
||||||
};
|
};
|
||||||
/* -----------------------------------------------------------------
|
/* -----------------------------------------------------------------
|
||||||
Initialization and module stuff
|
Initialization and module stuff
|
||||||
@ -1361,8 +1353,6 @@ static int __init vivi_init(void)
|
|||||||
dev->vidq.timeout.data = (unsigned long)dev;
|
dev->vidq.timeout.data = (unsigned long)dev;
|
||||||
init_timer(&dev->vidq.timeout);
|
init_timer(&dev->vidq.timeout);
|
||||||
|
|
||||||
vivi.current_norm = tvnorms[0].id;
|
|
||||||
|
|
||||||
ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
|
ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
|
||||||
printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
|
printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
/* Video standard functions */
|
/* Video standard functions */
|
||||||
extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
|
extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
|
||||||
|
extern char *v4l2_norm_to_name(v4l2_std_id id);
|
||||||
extern int v4l2_video_std_construct(struct v4l2_standard *vs,
|
extern int v4l2_video_std_construct(struct v4l2_standard *vs,
|
||||||
int id, char *name);
|
int id, char *name);
|
||||||
|
|
||||||
@ -81,12 +82,6 @@ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
|
|||||||
* This version moves redundant code from video device code to
|
* This version moves redundant code from video device code to
|
||||||
* the common handler
|
* the common handler
|
||||||
*/
|
*/
|
||||||
struct v4l2_tvnorm {
|
|
||||||
char *name;
|
|
||||||
v4l2_std_id id;
|
|
||||||
|
|
||||||
void *priv_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct video_device
|
struct video_device
|
||||||
{
|
{
|
||||||
@ -104,9 +99,8 @@ struct video_device
|
|||||||
int debug; /* Activates debug level*/
|
int debug; /* Activates debug level*/
|
||||||
|
|
||||||
/* Video standard vars */
|
/* Video standard vars */
|
||||||
int tvnormsize; /* Size of tvnorm array */
|
v4l2_std_id tvnorms; /* Supported tv norms */
|
||||||
v4l2_std_id current_norm; /* Current tvnorm */
|
v4l2_std_id current_norm; /* Current tvnorm */
|
||||||
struct v4l2_tvnorm *tvnorms;
|
|
||||||
|
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
void (*release)(struct video_device *vfd);
|
void (*release)(struct video_device *vfd);
|
||||||
@ -211,7 +205,7 @@ struct video_device
|
|||||||
/* Standard handling
|
/* Standard handling
|
||||||
G_STD and ENUMSTD are handled by videodev.c
|
G_STD and ENUMSTD are handled by videodev.c
|
||||||
*/
|
*/
|
||||||
int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id a);
|
int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
|
||||||
int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
|
int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
|
||||||
|
|
||||||
/* Input handling */
|
/* Input handling */
|
||||||
|
Loading…
Reference in New Issue
Block a user