Re: Kernel module: return a number from a device
- Reply: Rocky Hotas : "Re: Re: Kernel module: return a number from a device"
- In reply to: Rocky Hotas : "Kernel module: return a number from a device"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 07 Apr 2024 10:50:00 UTC
Rocky Hotas <rockyhotas@tilde.team> writes: > static int > rolld_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) > { > uint32_t random_out; > uint32_t random_item; > int error; > > random_item = arc4random(); > random_out = random_item % d_size; > > if ((error = uiomove(&random_out, 1, uio)) != 0) > uprintf("uiomove failed!\n"); > > return (error); > } Using a uint32_t will work on little-endian systems (such as amd64) because the least-significant byte, which is the only non-zero byte, comes first. On big-endian systems, it would simply always return 0. Furthermore, this won't only return one byte; rather, it will return one byte _at a time_, very inefficiently. This is why cat appears to hang. To truly only return one byte, you need to look at uio->uio_offset and return 0 without calling uiomove(), signaling EOF, if it is non-zero. In summary, you should write rolld_read() as: uint8_t roll = arc4random() % d_size; if (uio->uio_offset > 0) return (0); return (uiomove(&roll, 1, uio)); You can also use uiomove_frombuf(), which will take care of that check for you. It's a bit overkill when you're only writing a single byte, but if you wanted to output text instead of binary, you could use this: char roll[2]; roll[0] = '0' + arc4random() % d_size; roll[1] = '\n'; return (uiomove_frombuf(roll, sizeof(roll), uio)); Obviously, this will only work for d_size <= 9. For larger values, you will want to use snprintf(): char roll[16]; int len = snprintf(roll, sizeof(roll), "%d\n", arc4random() % d_size); return (uiomove_frombuf(roll, len, uio)); Have fun, DES -- Dag-Erling Smørgrav - des@FreeBSD.org