This is copied from the linux kernel with only some include changes so it works outside the kernel headers.