fred@rover.UUCP (Fred Christiansen) (08/28/87)
a co-worker is attempting to port a driver from System V/68 (SysV) to a Sun (Berkeley). he brought this question to me, which i can't answer. can someone help? if a user does a read(), like: n = read( fd, buf, sizeof( buf ) ); then inside a SysV kernel, u.u_base is the address of `buf', while u.u_count is `sizeof( buf )'. after the copyout(), i decrement u.u_count by the number of bytes copied. then, by someone between the driver read return and the read() return, someone subtracts u.u_count from `sizeof( buf )' so that the return value of read() is the number of bytes read. the co-worker has read Sun's device driver writer's guide, but does not understand (so cannot explain to me) the use of `struct uio' and `struct iovec'. under SunOS, read()'s are returning 0. what needs to get set so the real number of bytes read gets returned. thanks! -- Fred Christiansen ("Canajun, eh?") | seismo!noao!mcdsun!nud!fred (ARPA gate) Motorola Microcomputer Div., Tempe, AZ | utzoo!mnetor!mot!fred "The greatest thing a father can do for| ihnp4!mot!fred his children is to love their mother." | hplabs!motsj1!ellygroup ...
guy%gorodish@Sun.COM (Guy Harris) (08/29/87)
> if a user does a read(), like: > n = read( fd, buf, sizeof( buf ) ); > then inside a SysV kernel, u.u_base is the address of `buf', while > u.u_count is `sizeof( buf )'. 4.2BSD got rid of this crud (Global Variables Considered Harmful), and instead passes the equivalent information in the "uio" structure pointed to by the appropriate argument to the device driver (or other) routine. If your driver used to use "iomove", to make it work in a system that handles this in a 4.2BSD style it should be changed to use "uiomove". "iomove" handles updating "u.u_count"; "uiomove" handles updating "uio_resid" for the "uio" structure pointed to by the argument. The "uio_resid" member of that "uio" structure contains the byte count for the "read" or "write" (or the total byte count for scatter/gather operations), and should be decremented as data is transferred. The value when the operation is complete is what the "read", "write", etc. code uses to determine how much data is actually transferred. The "iomove" call iomove(addr, count, flag) turns into error = uiomove(addr, count, uioflag, uio) "uio" is the "uio" structure pointer passed to the driver. "uioflag" is a flag (an "enum", actually) indicating the type of I/O operation. If "flag" was B_READ, "uioflag" should be UIO_READ; if "flag" was B_WRITE, "uioflag" should be UIO_WRITE. The return value from "uiomove" is either 0 if there were no errors, or a UNIX "errno" code if there was an error; many routines in 4.2BSD were changed to return error codes rather than setting "u.u_error" (device driver routines, for example, are expected to return 0 or an error code, rather than returning no value and setting "u.u_error" to the error code if an error occurred). If the driver *didn't* use "iomove", but did the operations itself, the conversion can get a bit complicated *if* they intend to support the "readv" and "writev" system calls, which require the full "iovec" baggage. They would basically have to manually step through the "iovec" vector themselves. If they don't intend to support those calls, they can just cheat and use the first member of the "iovec" structure pointed to by the "uio_iov" member of the "uio" structure (which, for "read" or "write", is the *only* member). Essentially, "uio_resid" is the moral equivalent of "u.u_count", "uio_offset" is the moral equivalent of "u.u_offset", and in SunOS 3.2 and later (but not in 4.[23]BSD) "uio_fmode" is the moral equivalent of "u.u_fmode". "uio_seg" (renamed "uio_segflg" in 4.3BSD, and most likely in a future SunOS release), is the moral equivalent of "u.u_segflg", if the driver cares about it. The values are the same: 0 for user data space, 1 for system space, and (in 4.3BSD) 2 for user I space (if you have separate I&D space, which we don't). However, you should use the #defines in "uio.h" instead to make your code more readable. "u.u_base" does not have an equivalent in the "uio" structure, since the I/O operation could conceivably consist of several transfers to several non-contiguous areas. Each area is described by an "iovec" structure in the array whose first member is pointed to by the "uio_iov" member; "uio_iovcnt" is the number of members in that array. Each "iovec" structure has an "iov_base" member, which is the "u.u_base" *for that area*, and an "iov_len" member which is the length of that area. (When the driver routine is called, "uio_resid"s value is equal to the sum of the values of the "iov_len" members of all the "iovec" structures.) So the problem is probably that the driver isn't updating the "uio_resid" member of the "uio" structure passed to it. It should subtract the number of bytes it reads or writes from that value. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com