Hello,
ioctl(LPGETSTATUS) is known to put the status into an int. The usblp
driver has a problem in this area as it does not put it into an int but
into a char. Let's see :
from drivers/char/lp.c : lp_ioctl :
int status
copy_to_user((int *) arg, &status, sizeof(int))
from drivers/usb/printer.c : usblp_ioctl :
unsigned char status;
copy_to_user ((unsigned char *)arg, &status, 1)
Even though in most cases it can work unnoticed on little-endian
machines ;o), it's broken on non-little-endian machines (I got bitten on
PPC).
Attached are patches to fix this issue. These are against 2.4.18 and
2.5.21 (untested), upported from 2.4.12 (with 2.4.18 usb stack) which is
the one I've successfully tested. It works for me on PPC now (I'm
printing on USB Canon printers like the S100 using in-house
hardware...). Feedback is welcome,
Flavien.
--- linux-2.4.18/drivers/usb/printer.c Wed Oct 10 00:15:02 2001
+++ linux-2.4.18.fl/drivers/usb/printer.c Wed Jun 12 19:03:01 2002
@@ -295,7 +295,8 @@
{
struct usblp *usblp = file->private_data;
int length, err;
- unsigned char status;
+ unsigned char lpstatus;
+ int status;
int retval = 0;
down (&usblp->sem);
@@ -349,12 +350,13 @@
switch (cmd) {
case LPGETSTATUS:
- if (usblp_read_status(usblp, &status)) {
+ if (usblp_read_status(usblp, &lpstatus)) {
err("usblp%d: failed reading printer status",
usblp->minor);
retval = -EIO;
goto done;
}
- if (copy_to_user ((unsigned char *)arg, &status, 1))
+ status = lpstatus;
+ if (copy_to_user ((int *)arg, &status, sizeof(int)))
retval = -EFAULT;
break;
--- linux-2.5.21/drivers/usb/class/printer.c Sun Jun 9 07:27:45 2002
+++ linux-2.5.21.fl/drivers/usb/class/printer.c Wed Jun 12 16:08:08 2002
@@ -418,7 +418,8 @@
{
struct usblp *usblp = file->private_data;
int length, err, i;
- unsigned char status, newChannel;
+ unsigned char lpstatus, newChannel;
+ int status;
int twoints[2];
int retval = 0;
@@ -569,12 +570,13 @@
switch (cmd) {
case LPGETSTATUS:
- if (usblp_read_status(usblp, &status)) {
+ if (usblp_read_status(usblp, &lpstatus)) {
err("usblp%d: failed reading printer status",
usblp->minor);
retval = -EIO;
goto done;
}
- if (copy_to_user ((unsigned char *)arg, &status, 1))
+ status = lpstatus;
+ if (copy_to_user ((int *)arg, &status, sizeof(int)))
retval = -EFAULT;
break;