<commit_before>/* ced_ioc.c
 ioctl part of the 1401 usb device driver for linux.
 Copyright (C) 2010 Cambridge Electronic Design Ltd
 Author <NAME> (<EMAIL>)

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/page-flags.h>
#include <linux/pagemap.h>
#include <linux/jiffies.h>

#include "usb1401.h"

/****************************************************************************
** ced_flush_out_buff
**
** Empties the Output buffer and sets int lines. Used from user level only
****************************************************************************/
static void ced_flush_out_buff(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
		__func__, ced->current_state);

	/* Do nothing if hardware in trouble */
	if (ced->current_state == U14ERR_TIME)
		return;
	/* Kill off any pending I/O */
	/* CharSend_Cancel(ced);  */
	spin_lock_irq(&ced->char_out_lock);
	ced->num_output = 0;
	ced->out_buff_get = 0;
	ced->out_buff_put = 0;
	spin_unlock_irq(&ced->char_out_lock);
}

/****************************************************************************
**
** ced_flush_in_buff
**
** Empties the input buffer and sets int lines
****************************************************************************/
static void ced_flush_in_buff(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
		__func__, ced->current_state);
	if (ced->current_state == U14ERR_TIME)	/* Do nothing if hardware in trouble */
		return;
	/* Kill off any pending I/O */
	/*     CharRead_Cancel(pDevObject);  */
	spin_lock_irq(&ced->char_in_lock);
	ced->num_input = 0;
	ced->in_buff_get = 0;
	ced->in_buff_put = 0;
	spin_unlock_irq(&ced->char_in_lock);
}

/****************************************************************************
** ced_put_chars
**
** Utility routine to copy chars into the output buffer and fire them off.
** called from user mode, holds char_out_lock.
****************************************************************************/
static int ced_put_chars(struct ced_data *ced, const char *ch,
		    unsigned int count)
{
	int ret;

	spin_lock_irq(&ced->char_out_lock);	/*  get the output spin lock */
	if ((OUTBUF_SZ - ced->num_output) >= count) {
		unsigned int u;

		for (u = 0; u < count; u++) {
			ced->output_buffer[ced->out_buff_put++] = ch[u];
			if (ced->out_buff_put >= OUTBUF_SZ)
				ced->out_buff_put = 0;
		}
		ced->num_output += count;
		spin_unlock_irq(&ced->char_out_lock);
		ret = ced_send_chars(ced);	/*  ...give a chance to transmit data */
	} else {
		ret = U14ERR_NOOUT;	/*  no room at the out (ha-ha) */
		spin_unlock_irq(&ced->char_out_lock);
	}
	return ret;
}

/*****************************************************************************
** Add the data in "data" local pointer of length n to the output buffer, and
** trigger an output transfer if this is appropriate. User mode.
** Holds the io_mutex
*****************************************************************************/
int ced_send_string(struct ced_data *ced, const char __user *data,
	       unsigned int n)
{
	int ret = U14ERR_NOERROR;	/* assume all will be well */
	char buffer[OUTBUF_SZ + 1];	/* space in our address space */
					/* for characters             */
	if (n > OUTBUF_SZ)	/*  check space in local buffer... */
		return U14ERR_NOOUT;	/*  ...too many characters */
	if (copy_from_user(buffer, data, n))
		return -EFAULT;
	buffer[n] = 0;		/*  terminate for debug purposes */

	mutex_lock(&ced->io_mutex);	/*  Protect disconnect from new i/o */
	if (n > 0) {		/*  do nothing if nowt to do! */
		dev_dbg(&ced->interface->dev, "%s: n=%d>%s<\n",
			__func__, n, buffer);
		ret = ced_put_chars(ced, buffer, n);
	}

	ced_allowi(ced);		/*  make sure we have input int */
	mutex_unlock(&ced->io_mutex);

	return ret;
}

/****************************************************************************
** ced_send_char
**
** Sends a single character to the 1401. User mode, holds io_mutex.
****************************************************************************/
int ced_send_char(struct ced_data *ced, char c)
{
	int ret;

	mutex_lock(&ced->io_mutex);	/*  Protect disconnect from new i/o */
	ret = ced_put_chars(ced, &c, 1);
	dev_dbg(&ced->interface->dev, "ced_send_char >%c< (0x%02x)\n", c, c);
	ced_allowi(ced);	/*  Make sure char reads are running */
	mutex_unlock(&ced->io_mutex);
	return ret;
}

/***************************************************************************
**
** ced_get_state
**
**  Retrieves state information from the 1401, adjusts the 1401 state held
**  in the device extension to indicate the current 1401 type.
**
**  *state is updated with information about the 1401 state as returned by the
**         1401. The low byte is a code for what 1401 is doing:
**
**  0       normal 1401 operation
**  1       sending chars to host
**  2       sending block data to host
**  3       reading block data from host
**  4       sending an escape sequence to the host
**  0x80    1401 is executing self-test, in which case the upper word
**          is the last error code seen (or zero for no new error).
**
** *error is updated with error information if a self-test error code
**          is returned in the upper word of state.
**
**  both state and error are set to -1 if there are comms problems, and
**  to zero if there is a simple failure.
**
** return error code (U14ERR_NOERROR for OK)
*/
int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error)
{
	int got;

	dev_dbg(&ced->interface->dev, "%s: entry\n", __func__);

	*state = 0xFFFFFFFF;	/*  Start off with invalid state */
	got = usb_control_msg(ced->udev, usb_rcvctrlpipe(ced->udev, 0),
			       GET_STATUS, (D_TO_H | VENDOR | DEVREQ), 0, 0,
			       ced->stat_buf, sizeof(ced->stat_buf), HZ);
	if (got != sizeof(ced->stat_buf)) {
		dev_err(&ced->interface->dev,
			"%s: FAILED, return code %d\n", __func__, got);
		/* Indicate that things are very wrong indeed */
		ced->current_state = U14ERR_TIME;
		*state = 0;	/*  Force status values to a known state */
		*error = 0;
	} else {
		int device;

		dev_dbg(&ced->interface->dev,
			"%s: Success, state: 0x%x, 0x%x\n",
			__func__, ced->stat_buf[0], ced->stat_buf[1]);

		/* Return the state values to the calling code */
		*state = ced->stat_buf[0];

		*error = ced->stat_buf[1];

		/* 1401 type code value */
		device = ced->udev->descriptor.bcdDevice >> 8;
		switch (device) {	/*  so we can clean up current state */
		case 0:
			ced->current_state = U14ERR_U1401;
			break;

		default: /* allow lots of device codes for future 1401s */
			if ((device >= 1) && (device <= 23))
				ced->current_state = (short)(device + 6);
			else
				ced->current_state = U14ERR_ILL;
			break;
		}
	}

	return ced->current_state >= 0 ? U14ERR_NOERROR : ced->current_state;
}

/****************************************************************************
** ced_read_write_cancel
**
** Kills off staged read\write request from the USB if one is pending.
****************************************************************************/
int ced_read_write_cancel(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: entry %d\n",
		__func__, ced->staged_urb_pending);
#ifdef NOT_WRITTEN_YET
	int ntStatus = STATUS_SUCCESS;
	bool bResult = false;
	unsigned int i;
	/*  We can fill this in when we know how we will implement the staged transfer stuff */
	spin_lock_irq(&ced->staged_lock);

	if (ced->staged_urb_pending) {	/*  anything to be cancelled? May need more... */
		dev_info(&ced->interface - dev,
			 "ced_read_write_cancel about to cancel Urb\n");
		/* Clear the staging done flag */
		/* KeClearEvent(&ced->StagingDoneEvent); */
		USB_ASSERT(ced->pStagedIrp != NULL);

		/*  Release the spinlock first otherwise the completion routine may hang */
		/*   on the spinlock while this function hands waiting for the event. */
		spin_unlock_irq(&ced->staged_lock);
		bResult = IoCancelIrp(ced->pStagedIrp);	/*  Actually do the cancel */
		if (bResult) {
			LARGE_INTEGER timeout;

			timeout.QuadPart = -10000000;	/*  Use a timeout of 1 second */
			dev_info(&ced->interface - dev,
				 "%s: about to wait till done\n", __func__);
			ntStatus =
			    KeWaitForSingleObject(&ced->StagingDoneEvent,
						  Executive, KernelMode, FALSE,
						  &timeout);
		} else {
			dev_info(&ced->interface - dev,
				 "%s: cancellation failed\n", __func__);
			ntStatus = U14ERR_FAIL;
		}
		USB_KdPrint(DBGLVL_DEFAULT,
			    ("ced_read_write_cancel ntStatus = 0x%x decimal %d\n",
			     ntStatus, ntStatus));
	} else
		spin_unlock_irq(&ced->staged_lock);

	dev_info(&ced->interface - dev, "%s: done\n", __func__);
	return ntStatus;
#else
	return U14ERR_NOERROR;
#endif

}

/***************************************************************************
** ced_in_self_test - utility to check in self test. Return 1 for ST, 0 for not
** or a -ve error code if we failed for some reason.
***************************************************************************/
static int ced_in_self_test(struct ced_data *ced, unsigned int *stat)
{
	unsigned int state, error;
	int ret = ced_get_state(ced, &state, &error); /* see if in self-test */

	if (ret == U14ERR_NOERROR)	/*  if all still OK */
		ret = (state == (unsigned int)-1) ||	/*  TX problem or... */
		    ((state & 0xff) == 0x80);	/*  ...self test */
	*stat = state;	/*  return actual state */
	return ret;
}

/***************************************************************************
** ced_is_1401 - ALWAYS CALLED HOLDING THE io_mutex
**
** Tests for the current state of the 1401. Sets current_state:
**
**  U14ERR_NOIF  1401  i/f card not installed (not done here)
**  U14ERR_OFF   1401  apparently not switched on
**  U14ERR_NC    1401  appears to be not connected
**  U14ERR_ILL   1401  if it is there its not very well at all
**  U14ERR_TIME  1401  appears OK, but doesn't communicate - very bad
**  U14ERR_STD   1401  OK and ready for use
**  U14ERR_PLUS  1401+ OK and ready for use
**  U14ERR_U1401 Micro1401 OK and ready for use
**  U14ERR_POWER Power1401 OK and ready for use
**  U14ERR_U14012 Micro1401 mkII OK and ready for use
**
**  Returns TRUE if a 1401 detected and OK, else FALSE
****************************************************************************/
static bool ced_is_1401(struct ced_data *ced)
{
	int ret;

	dev_dbg(&ced->interface->dev, "%s\n", __func__);

	ced_draw_down(ced);	/*  wait for, then kill outstanding Urbs */
	ced_flush_in_buff(ced);	/*  Clear out input buffer & pipe */
	ced_flush_out_buff(ced);	/*  Clear output buffer & pipe */

	/* The next call returns 0 if OK, but has returned 1 in the past, */
	/* meaning that usb_unlock_device() is needed... now it always is */
	ret = usb_lock_device_for_reset(ced->udev, ced->interface);

	/*  release the io_mutex because if we don't, we will deadlock due to */
	/* system calls back into the driver.				      */
	mutex_unlock(&ced->io_mutex); /* locked, so we will not get */
				      /* system calls		    */
	if (ret >= 0) {	/*  if we failed */
		ret = usb_reset_device(ced->udev); /* try to do the reset */
		usb_unlock_device(ced->udev);	/* undo the lock */
	}

	mutex_lock(&ced->io_mutex);	/*  hold stuff off while we wait */
	ced->dma_flag = MODE_CHAR;	/*  Clear DMA mode flag regardless! */
	if (ret == 0) {	/*  if all is OK still */
		unsigned int state;

		ret = ced_in_self_test(ced, &state); /* see if likely in */
						     /* self test 	 */
		if (ret > 0) {	/*  do we need to wait for self-test? */
			/* when to give up */
			unsigned long timeout = jiffies + 30 * HZ;

			while ((ret > 0) && time_before(jiffies, timeout)) {
				schedule();	/*  let other stuff run */

				/* see if done yet */
				ret = ced_in_self_test(ced, &state);
			}
		}

		if (ret == 0)	/*  if all is OK... */
			/* then success is that the state is 0 */
			ret = state == 0;
	} else
		ret = 0;	/*  we failed */
	ced->force_reset = false;	/*  Clear forced reset flag now */

	return ret > 0;
}

/****************************************************************************
** ced_quick_check  - ALWAYS CALLED HOLDING THE io_mutex<commit_msg>staging: ced1401: ced_ioc.c: remove space before tabs<commit_after>/* ced_ioc.c
 ioctl part of the 1401 usb device driver for linux.
 Copyright (C) 2010 Cambridge Electronic Design Ltd
 Author <NAME> (<EMAIL>)

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/page-flags.h>
#include <linux/pagemap.h>
#include <linux/jiffies.h>

#include "usb1401.h"

/****************************************************************************
** ced_flush_out_buff
**
** Empties the Output buffer and sets int lines. Used from user level only
****************************************************************************/
static void ced_flush_out_buff(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
		__func__, ced->current_state);

	/* Do nothing if hardware in trouble */
	if (ced->current_state == U14ERR_TIME)
		return;
	/* Kill off any pending I/O */
	/* CharSend_Cancel(ced);  */
	spin_lock_irq(&ced->char_out_lock);
	ced->num_output = 0;
	ced->out_buff_get = 0;
	ced->out_buff_put = 0;
	spin_unlock_irq(&ced->char_out_lock);
}

/****************************************************************************
**
** ced_flush_in_buff
**
** Empties the input buffer and sets int lines
****************************************************************************/
static void ced_flush_in_buff(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: current_state=%d\n",
		__func__, ced->current_state);
	if (ced->current_state == U14ERR_TIME)	/* Do nothing if hardware in trouble */
		return;
	/* Kill off any pending I/O */
	/*     CharRead_Cancel(pDevObject);  */
	spin_lock_irq(&ced->char_in_lock);
	ced->num_input = 0;
	ced->in_buff_get = 0;
	ced->in_buff_put = 0;
	spin_unlock_irq(&ced->char_in_lock);
}

/****************************************************************************
** ced_put_chars
**
** Utility routine to copy chars into the output buffer and fire them off.
** called from user mode, holds char_out_lock.
****************************************************************************/
static int ced_put_chars(struct ced_data *ced, const char *ch,
		    unsigned int count)
{
	int ret;

	spin_lock_irq(&ced->char_out_lock);	/*  get the output spin lock */
	if ((OUTBUF_SZ - ced->num_output) >= count) {
		unsigned int u;

		for (u = 0; u < count; u++) {
			ced->output_buffer[ced->out_buff_put++] = ch[u];
			if (ced->out_buff_put >= OUTBUF_SZ)
				ced->out_buff_put = 0;
		}
		ced->num_output += count;
		spin_unlock_irq(&ced->char_out_lock);
		ret = ced_send_chars(ced);	/*  ...give a chance to transmit data */
	} else {
		ret = U14ERR_NOOUT;	/*  no room at the out (ha-ha) */
		spin_unlock_irq(&ced->char_out_lock);
	}
	return ret;
}

/*****************************************************************************
** Add the data in "data" local pointer of length n to the output buffer, and
** trigger an output transfer if this is appropriate. User mode.
** Holds the io_mutex
*****************************************************************************/
int ced_send_string(struct ced_data *ced, const char __user *data,
	       unsigned int n)
{
	int ret = U14ERR_NOERROR;	/* assume all will be well */
	char buffer[OUTBUF_SZ + 1];	/* space in our address space */
					/* for characters             */
	if (n > OUTBUF_SZ)	/*  check space in local buffer... */
		return U14ERR_NOOUT;	/*  ...too many characters */
	if (copy_from_user(buffer, data, n))
		return -EFAULT;
	buffer[n] = 0;		/*  terminate for debug purposes */

	mutex_lock(&ced->io_mutex);	/*  Protect disconnect from new i/o */
	if (n > 0) {		/*  do nothing if nowt to do! */
		dev_dbg(&ced->interface->dev, "%s: n=%d>%s<\n",
			__func__, n, buffer);
		ret = ced_put_chars(ced, buffer, n);
	}

	ced_allowi(ced);		/*  make sure we have input int */
	mutex_unlock(&ced->io_mutex);

	return ret;
}

/****************************************************************************
** ced_send_char
**
** Sends a single character to the 1401. User mode, holds io_mutex.
****************************************************************************/
int ced_send_char(struct ced_data *ced, char c)
{
	int ret;

	mutex_lock(&ced->io_mutex);	/*  Protect disconnect from new i/o */
	ret = ced_put_chars(ced, &c, 1);
	dev_dbg(&ced->interface->dev, "ced_send_char >%c< (0x%02x)\n", c, c);
	ced_allowi(ced);	/*  Make sure char reads are running */
	mutex_unlock(&ced->io_mutex);
	return ret;
}

/***************************************************************************
**
** ced_get_state
**
**  Retrieves state information from the 1401, adjusts the 1401 state held
**  in the device extension to indicate the current 1401 type.
**
**  *state is updated with information about the 1401 state as returned by the
**         1401. The low byte is a code for what 1401 is doing:
**
**  0       normal 1401 operation
**  1       sending chars to host
**  2       sending block data to host
**  3       reading block data from host
**  4       sending an escape sequence to the host
**  0x80    1401 is executing self-test, in which case the upper word
**          is the last error code seen (or zero for no new error).
**
** *error is updated with error information if a self-test error code
**          is returned in the upper word of state.
**
**  both state and error are set to -1 if there are comms problems, and
**  to zero if there is a simple failure.
**
** return error code (U14ERR_NOERROR for OK)
*/
int ced_get_state(struct ced_data *ced, __u32 *state, __u32 *error)
{
	int got;

	dev_dbg(&ced->interface->dev, "%s: entry\n", __func__);

	*state = 0xFFFFFFFF;	/*  Start off with invalid state */
	got = usb_control_msg(ced->udev, usb_rcvctrlpipe(ced->udev, 0),
			       GET_STATUS, (D_TO_H | VENDOR | DEVREQ), 0, 0,
			       ced->stat_buf, sizeof(ced->stat_buf), HZ);
	if (got != sizeof(ced->stat_buf)) {
		dev_err(&ced->interface->dev,
			"%s: FAILED, return code %d\n", __func__, got);
		/* Indicate that things are very wrong indeed */
		ced->current_state = U14ERR_TIME;
		*state = 0;	/*  Force status values to a known state */
		*error = 0;
	} else {
		int device;

		dev_dbg(&ced->interface->dev,
			"%s: Success, state: 0x%x, 0x%x\n",
			__func__, ced->stat_buf[0], ced->stat_buf[1]);

		/* Return the state values to the calling code */
		*state = ced->stat_buf[0];

		*error = ced->stat_buf[1];

		/* 1401 type code value */
		device = ced->udev->descriptor.bcdDevice >> 8;
		switch (device) {	/*  so we can clean up current state */
		case 0:
			ced->current_state = U14ERR_U1401;
			break;

		default: /* allow lots of device codes for future 1401s */
			if ((device >= 1) && (device <= 23))
				ced->current_state = (short)(device + 6);
			else
				ced->current_state = U14ERR_ILL;
			break;
		}
	}

	return ced->current_state >= 0 ? U14ERR_NOERROR : ced->current_state;
}

/****************************************************************************
** ced_read_write_cancel
**
** Kills off staged read\write request from the USB if one is pending.
****************************************************************************/
int ced_read_write_cancel(struct ced_data *ced)
{
	dev_dbg(&ced->interface->dev, "%s: entry %d\n",
		__func__, ced->staged_urb_pending);
#ifdef NOT_WRITTEN_YET
	int ntStatus = STATUS_SUCCESS;
	bool bResult = false;
	unsigned int i;
	/*  We can fill this in when we know how we will implement the staged transfer stuff */
	spin_lock_irq(&ced->staged_lock);

	if (ced->staged_urb_pending) {	/*  anything to be cancelled? May need more... */
		dev_info(&ced->interface - dev,
			 "ced_read_write_cancel about to cancel Urb\n");
		/* Clear the staging done flag */
		/* KeClearEvent(&ced->StagingDoneEvent); */
		USB_ASSERT(ced->pStagedIrp != NULL);

		/*  Release the spinlock first otherwise the completion routine may hang */
		/*   on the spinlock while this function hands waiting for the event. */
		spin_unlock_irq(&ced->staged_lock);
		bResult = IoCancelIrp(ced->pStagedIrp);	/*  Actually do the cancel */
		if (bResult) {
			LARGE_INTEGER timeout;

			timeout.QuadPart = -10000000;	/*  Use a timeout of 1 second */
			dev_info(&ced->interface - dev,
				 "%s: about to wait till done\n", __func__);
			ntStatus =
			    KeWaitForSingleObject(&ced->StagingDoneEvent,
						  Executive, KernelMode, FALSE,
						  &timeout);
		} else {
			dev_info(&ced->interface - dev,
				 "%s: cancellation failed\n", __func__);
			ntStatus = U14ERR_FAIL;
		}
		USB_KdPrint(DBGLVL_DEFAULT,
			    ("ced_read_write_cancel ntStatus = 0x%x decimal %d\n",
			     ntStatus, ntStatus));
	} else
		spin_unlock_irq(&ced->staged_lock);

	dev_info(&ced->interface - dev, "%s: done\n", __func__);
	return ntStatus;
#else
	return U14ERR_NOERROR;
#endif

}

/***************************************************************************
** ced_in_self_test - utility to check in self test. Return 1 for ST, 0 for not
** or a -ve error code if we failed for some reason.
***************************************************************************/
static int ced_in_self_test(struct ced_data *ced, unsigned int *stat)
{
	unsigned int state, error;
	int ret = ced_get_state(ced, &state, &error); /* see if in self-test */

	if (ret == U14ERR_NOERROR)	/*  if all still OK */
		ret = (state == (unsigned int)-1) ||	/*  TX problem or... */
		    ((state & 0xff) == 0x80);	/*  ...self test */
	*stat = state;	/*  return actual state */
	return ret;
}

/***************************************************************************
** ced_is_1401 - ALWAYS CALLED HOLDING THE io_mutex
**
** Tests for the current state of the 1401. Sets current_state:
**
**  U14ERR_NOIF  1401  i/f card not installed (not done here)
**  U14ERR_OFF   1401  apparently not switched on
**  U14ERR_NC    1401  appears to be not connected
**  U14ERR_ILL   1401  if it is there its not very well at all
**  U14ERR_TIME  1401  appears OK, but doesn't communicate - very bad
**  U14ERR_STD   1401  OK and ready for use
**  U14ERR_PLUS  1401+ OK and ready for use
**  U14ERR_U1401 Micro1401 OK and ready for use
**  U14ERR_POWER Power1401 OK and ready for use
**  U14ERR_U14012 Micro1401 mkII OK and ready for use
**
**  Returns TRUE if a 1401 detected and OK, else FALSE
****************************************************************************/
static bool ced_is_1401(struct ced_data *ced)
{
	int ret;

	dev_dbg(&ced->interface->dev, "%s\n", __func__);

	ced_draw_down(ced);	/*  wait for, then kill outstanding Urbs */
	ced_flush_in_buff(ced);	/*  Clear out input buffer & pipe */
	ced_flush_out_buff(ced);	/*  Clear output buffer & pipe */

	/* The next call returns 0 if OK, but has returned 1 in the past, */
	/* meaning that usb_unlock_device() is needed... now it always is */
	ret = usb_lock_device_for_reset(ced->udev, ced->interface);

	/*  release the io_mutex because if we don't, we will deadlock due to */
	/* system calls back into the driver.				      */
	mutex_unlock(&ced->io_mutex); /* locked, so we will not get */
				      /* system calls		    */
	if (ret >= 0) {	/*  if we failed */
		ret = usb_reset_device(ced->udev); /* try to do the reset */
		usb_unlock_device(ced->udev);	/* undo the lock */
	}

	mutex_lock(&ced->io_mutex);	/*  hold stuff off while we wait */
	ced->dma_flag = MODE_CHAR;	/*  Clear DMA mode flag regardless! */
	if (ret == 0) {	/*  if all is OK still */
		unsigned int state;

		ret = ced_in_self_test(ced, &state); /* see if likely in */
						     /* self test	 */
		if (ret > 0) {	/*  do we need to wait for self-test? */
			/* when to give up */
			unsigned long timeout = jiffies + 30 * HZ;

			while ((ret > 0) && time_before(jiffies, timeout)) {
				schedule();	/*  let other stuff run */

				/* see if done yet */
				ret = ced_in_self_test(ced, &state);
			}
		}

		if (ret == 0)	/*  if all is OK... */
			/* then success is that the state is 0 */
			ret = state == 0;
	} else
		ret = 0;	/*  we failed */
	ced->force_reset = false;	/*  Clear forced reset flag now */

	return ret > 0;
}

/****************************************************************************
** ced_quick_check  - ALWAYS CALLED HOLDING THE io_mutex
{'fraction_non_alphanumeric': 0.21980741714683477, 'fraction_numerical': 0.020263737963571678, 'mean_word_length': 3.8454187745924675, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 223, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4102246', 'n_tokens_mistral': 9069, 'n_tokens_neox': 8127, 'n_words': 2649}